From 6431787de1709fbd347290cdaf851bab930afa46 Mon Sep 17 00:00:00 2001 From: Jeramy Soucy Date: Tue, 11 Apr 2023 13:19:41 -0400 Subject: [PATCH 01/23] Bump ssri 6.0.1 to 6.0.2 (#154595) Bumps the `ssri 6.0.1 `dev dependency to version `6.0.2`. --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 90493ed9ea652..48bd72635353d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -26262,9 +26262,9 @@ sshpk@^1.14.1: tweetnacl "~0.14.0" ssri@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" - integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== + version "6.0.2" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5" + integrity sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q== dependencies: figgy-pudding "^3.5.1" From db5ad716374adbf78bb256b74d5eca349ca6c8be Mon Sep 17 00:00:00 2001 From: Karl Godard Date: Tue, 11 Apr 2023 10:47:58 -0700 Subject: [PATCH 02/23] [D4C] Further cloud_defend policy validation work (#154616) ## Summary Adds some additional validation to the yaml editor for both string byte length checks as well as combined maximum allowed selectors and responses by type. ### Checklist Delete any items that are not applicable to this PR. - [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) ### Screenshots ![image](https://user-images.githubusercontent.com/16198204/230976116-881bf152-6af9-45ac-9c09-f8ad05d69795.png) ![image](https://user-images.githubusercontent.com/16198204/230976299-e7128486-a4a4-42d4-b979-3507b429535b.png) ![image](https://user-images.githubusercontent.com/16198204/230977899-61b66109-ded3-4c1d-9de9-3fa55699f5ae.png) --- .../cloud_defend/public/common/constants.ts | 4 +- .../cloud_defend/public/common/utils.ts | 78 +++++++++++++ .../control_general_view/index.test.tsx | 17 ++- .../components/control_general_view/index.tsx | 30 ++++- .../control_general_view/translations.ts | 7 -- .../index.test.tsx | 4 +- .../control_general_view_selector/index.tsx | 38 +----- .../components/control_settings/index.tsx | 7 +- .../control_yaml_view/index.test.tsx | 45 +++++++- .../components/control_yaml_view/index.tsx | 109 ++++++++++++------ .../control_yaml_view/translations.ts | 6 +- .../plugins/cloud_defend/public/test/mocks.ts | 47 ++++++++ x-pack/plugins/cloud_defend/public/types.ts | 10 +- .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 16 files changed, 307 insertions(+), 98 deletions(-) diff --git a/x-pack/plugins/cloud_defend/public/common/constants.ts b/x-pack/plugins/cloud_defend/public/common/constants.ts index e193d7e005b66..48b3ccde479d7 100644 --- a/x-pack/plugins/cloud_defend/public/common/constants.ts +++ b/x-pack/plugins/cloud_defend/public/common/constants.ts @@ -7,9 +7,9 @@ export const DEFAULT_VISIBLE_ROWS_PER_PAGE = 10; // generic default # of table rows to show (currently we only have a list of policies) export const LOCAL_STORAGE_PAGE_SIZE = 'cloudDefend:userPageSize'; export const VALID_SELECTOR_NAME_REGEX = /^[a-z0-9][a-z0-9_\-]*$/i; // alphanumberic (no - or _ allowed on first char) +export const MAX_SELECTORS_AND_RESPONSES_PER_TYPE = 64; export const MAX_SELECTOR_NAME_LENGTH = 128; // chars -export const MAX_CONDITION_VALUE_LENGTH_BYTES = 511; -export const MAX_FILE_PATH_VALUE_LENGTH_BYTES = 255; +export const MAX_CONDITION_VALUE_LENGTH_BYTES = 511; // max length for all condition values. some props override this in cloud_defend/public/types.ts // TODO: temporary until I change condition value length checks in the yaml editor view to be byte based. export const MAX_CONDITION_VALUE_LENGTH = 64; diff --git a/x-pack/plugins/cloud_defend/public/common/utils.ts b/x-pack/plugins/cloud_defend/public/common/utils.ts index ea5ee1194d850..f85f67125b7a9 100644 --- a/x-pack/plugins/cloud_defend/public/common/utils.ts +++ b/x-pack/plugins/cloud_defend/public/common/utils.ts @@ -6,6 +6,7 @@ */ import yaml from 'js-yaml'; import { NewPackagePolicy } from '@kbn/fleet-plugin/public'; +import { i18n } from '@kbn/i18n'; import { Selector, Response, @@ -17,6 +18,10 @@ import { SelectorConditionsMap, SelectorCondition, } from '../types'; +import { + MAX_CONDITION_VALUE_LENGTH_BYTES, + MAX_SELECTORS_AND_RESPONSES_PER_TYPE, +} from './constants'; export function getInputFromPolicy(policy: NewPackagePolicy, inputId: string) { return policy.inputs.find((input) => input.type === inputId); @@ -49,6 +54,79 @@ export function conditionCombinationInvalid( return !!invalid; } +type TotalByType = { + [key in SelectorType]: number; +}; + +export function getTotalsByType(selectors: Selector[], responses: Response[]) { + const totalsByType: TotalByType = { process: 0, file: 0 }; + + selectors.forEach((selector) => { + totalsByType[selector.type]++; + }); + + responses.forEach((response) => { + totalsByType[response.type]++; + }); + + return totalsByType; +} + +export function validateMaxSelectorsAndResponses(selectors: Selector[], responses: Response[]) { + const errors: string[] = []; + const totalsByType = getTotalsByType(selectors, responses); + + // check selectors + responses doesn't exceed MAX_SELECTORS_AND_RESPONSES_PER_TYPE + Object.values(totalsByType).forEach((count) => { + if (count > MAX_SELECTORS_AND_RESPONSES_PER_TYPE) { + errors.push( + i18n.translate('xpack.cloudDefend.errorMaxSelectorsResponsesExceeded', { + defaultMessage: + 'You cannot exceed {max} selectors + responses for a given type e.g file, process', + values: { max: MAX_SELECTORS_AND_RESPONSES_PER_TYPE }, + }) + ); + } + }); + + return errors; +} + +export function validateStringValuesForCondition(condition: SelectorCondition, values: string[]) { + const errors: string[] = []; + const maxValueBytes = + SelectorConditionsMap[condition].maxValueBytes || MAX_CONDITION_VALUE_LENGTH_BYTES; + + const { pattern, patternError } = SelectorConditionsMap[condition]; + + values.forEach((value) => { + if (pattern && !new RegExp(pattern).test(value)) { + if (patternError) { + errors.push(patternError); + } else { + errors.push( + i18n.translate('xpack.cloudDefend.errorGenericRegexFailure', { + defaultMessage: '"{condition}" values must match the pattern: /{pattern}/', + values: { condition, pattern }, + }) + ); + } + } + + const bytes = new Blob([value]).size; + if (bytes > maxValueBytes) { + errors.push( + i18n.translate('xpack.cloudDefend.errorMaxValueBytesExceeded', { + defaultMessage: '"{condition}" values cannot exceed {maxValueBytes} bytes', + values: { condition, maxValueBytes }, + }) + ); + } + }); + + return errors; +} + export function getRestrictedValuesForCondition( type: SelectorType, condition: SelectorCondition diff --git a/x-pack/plugins/cloud_defend/public/components/control_general_view/index.test.tsx b/x-pack/plugins/cloud_defend/public/components/control_general_view/index.test.tsx index 5f53d7ede6130..7606f1e2d0c1d 100644 --- a/x-pack/plugins/cloud_defend/public/components/control_general_view/index.test.tsx +++ b/x-pack/plugins/cloud_defend/public/components/control_general_view/index.test.tsx @@ -10,7 +10,11 @@ import { render, waitFor } from '@testing-library/react'; import { coreMock } from '@kbn/core/public/mocks'; import userEvent from '@testing-library/user-event'; import { TestProvider } from '../../test/test_provider'; -import { getCloudDefendNewPolicyMock, MOCK_YAML_INVALID_CONFIGURATION } from '../../test/mocks'; +import { + getCloudDefendNewPolicyMock, + MOCK_YAML_INVALID_CONFIGURATION, + MOCK_YAML_TOO_MANY_FILE_SELECTORS_RESPONSES, +} from '../../test/mocks'; import { ControlGeneralView } from '.'; import { getInputFromPolicy } from '../../common/utils'; import { INPUT_CONTROL } from '../../../common/constants'; @@ -156,4 +160,15 @@ describe('', () => { expect(queryAllByTestId('cloud-defend-selector')).toHaveLength(0); expect(queryAllByTestId('cloud-defend-response')).toHaveLength(0); }); + + it('prevents the user from adding more than MAX_SELECTORS_AND_RESPONSES_PER_TYPE', async () => { + const { getByTestId } = render( + + ); + + userEvent.click(getByTestId('cloud-defend-btnAddSelector')); + expect(getByTestId('cloud-defend-btnAddFileSelector')).toBeDisabled(); + }); }); diff --git a/x-pack/plugins/cloud_defend/public/components/control_general_view/index.tsx b/x-pack/plugins/cloud_defend/public/components/control_general_view/index.tsx index 9eefe032f27f6..72a182820ae89 100644 --- a/x-pack/plugins/cloud_defend/public/components/control_general_view/index.tsx +++ b/x-pack/plugins/cloud_defend/public/components/control_general_view/index.tsx @@ -24,22 +24,26 @@ import { getSelectorsAndResponsesFromYaml, getDefaultSelectorByType, getDefaultResponseByType, + getTotalsByType, } from '../../common/utils'; import { SelectorType, Selector, Response, ViewDeps } from '../../types'; import * as i18n from './translations'; import { ControlGeneralViewSelector } from '../control_general_view_selector'; import { ControlGeneralViewResponse } from '../control_general_view_response'; +import { MAX_SELECTORS_AND_RESPONSES_PER_TYPE } from '../../common/constants'; interface AddSelectorButtonProps { type: 'Selector' | 'Response'; onSelectType(type: SelectorType): void; selectors: Selector[]; + responses: Response[]; } /** * dual purpose button for adding selectors and responses by type */ -const AddButton = ({ type, onSelectType, selectors }: AddSelectorButtonProps) => { +const AddButton = ({ type, onSelectType, selectors, responses }: AddSelectorButtonProps) => { + const totalsByType = useMemo(() => getTotalsByType(selectors, responses), [responses, selectors]); const [isPopoverOpen, setPopover] = useState(false); const onButtonClick = () => { setPopover(!isPopoverOpen); @@ -84,7 +88,10 @@ const AddButton = ({ type, onSelectType, selectors }: AddSelectorButtonProps) => key={`addFile${type}`} icon="document" onClick={addFile} - disabled={type === 'Response' && selectorCounts.file === 0} + disabled={ + (type === 'Response' && selectorCounts.file === 0) || + totalsByType.file >= MAX_SELECTORS_AND_RESPONSES_PER_TYPE + } data-test-subj={`cloud-defend-btnAddFile${type}`} > {isSelector ? i18n.fileSelector : i18n.fileResponse} @@ -93,7 +100,10 @@ const AddButton = ({ type, onSelectType, selectors }: AddSelectorButtonProps) => key={`addProcess${type}`} icon="gear" onClick={addProcess} - disabled={type === 'Response' && selectorCounts.process === 0} + disabled={ + (type === 'Response' && selectorCounts.process === 0) || + totalsByType.process >= MAX_SELECTORS_AND_RESPONSES_PER_TYPE + } data-test-subj={`cloud-defend-btnAddProcess${type}`} > {isSelector ? i18n.processSelector : i18n.processResponse} @@ -343,7 +353,12 @@ export const ControlGeneralView = ({ policy, onChange, show }: ViewDeps) => { ); })} - + @@ -371,7 +386,12 @@ export const ControlGeneralView = ({ policy, onChange, show }: ViewDeps) => { ); })} - + ); diff --git a/x-pack/plugins/cloud_defend/public/components/control_general_view/translations.ts b/x-pack/plugins/cloud_defend/public/components/control_general_view/translations.ts index 79975f603b4ae..fc37da2fc6c86 100644 --- a/x-pack/plugins/cloud_defend/public/components/control_general_view/translations.ts +++ b/x-pack/plugins/cloud_defend/public/components/control_general_view/translations.ts @@ -148,13 +148,6 @@ export const errorValueRequired = i18n.translate('xpack.cloudDefend.errorValueRe defaultMessage: 'At least one value is required.', }); -export const errorValueLengthExceeded = i18n.translate( - 'xpack.cloudDefend.errorValueLengthExceeded', - { - defaultMessage: 'Values must not exceed 32 characters.', - } -); - export const getSelectorIconTooltip = (type: SelectorType) => { switch (type) { case 'process': diff --git a/x-pack/plugins/cloud_defend/public/components/control_general_view_selector/index.test.tsx b/x-pack/plugins/cloud_defend/public/components/control_general_view_selector/index.test.tsx index e469bc0591d16..4d3cfd0aa7623 100644 --- a/x-pack/plugins/cloud_defend/public/components/control_general_view_selector/index.test.tsx +++ b/x-pack/plugins/cloud_defend/public/components/control_general_view_selector/index.test.tsx @@ -189,7 +189,7 @@ describe('', () => { throw new Error("Can't find input"); } - expect(getByText(i18n.errorValueLengthExceeded)).toBeTruthy(); + expect(getByText('"containerImageName" values cannot exceed 511 bytes')).toBeTruthy(); }); it('prevents targetFilePath conditions from having values that exceed MAX_FILE_PATH_VALUE_LENGTH_BYTES', async () => { @@ -212,7 +212,7 @@ describe('', () => { throw new Error("Can't find input"); } - expect(getByText(i18n.errorValueLengthExceeded)).toBeTruthy(); + expect(getByText('"targetFilePath" values cannot exceed 255 bytes')).toBeTruthy(); }); it('shows an error if condition values fail their pattern regex', async () => { diff --git a/x-pack/plugins/cloud_defend/public/components/control_general_view_selector/index.tsx b/x-pack/plugins/cloud_defend/public/components/control_general_view_selector/index.tsx index 0b3b6f9acc162..6119e31386b5e 100644 --- a/x-pack/plugins/cloud_defend/public/components/control_general_view_selector/index.tsx +++ b/x-pack/plugins/cloud_defend/public/components/control_general_view_selector/index.tsx @@ -25,7 +25,6 @@ import { EuiText, EuiCheckbox, } from '@elastic/eui'; -import { i18n as i18nLib } from '@kbn/i18n'; import { useStyles } from './styles'; import { ControlGeneralViewSelectorDeps, @@ -40,16 +39,10 @@ import { getSelectorTypeIcon, conditionCombinationInvalid, getRestrictedValuesForCondition, + validateStringValuesForCondition, } from '../../common/utils'; import * as i18n from '../control_general_view/translations'; -import { - VALID_SELECTOR_NAME_REGEX, - MAX_SELECTOR_NAME_LENGTH, - MAX_CONDITION_VALUE_LENGTH_BYTES, - MAX_FILE_PATH_VALUE_LENGTH_BYTES, -} from '../../common/constants'; - -const { translate } = i18nLib; +import { VALID_SELECTOR_NAME_REGEX, MAX_SELECTOR_NAME_LENGTH } from '../../common/constants'; interface ConditionProps { label: string; @@ -290,30 +283,11 @@ export const ControlGeneralViewSelector = ({ errors.push(i18n.errorValueRequired); } - const { pattern, patternError } = SelectorConditionsMap[prop]; - - values.forEach((value) => { - const bytes = new Blob([value]).size; + const stringValueErrors = validateStringValuesForCondition(prop, values); - if (pattern && !new RegExp(pattern).test(value)) { - if (patternError) { - errors.push(patternError); - } else { - errors.push( - translate('xpack.cloudDefend.errorGenericRegexFailure', { - defaultMessage: '"{prop}" values must match the pattern: /{pattern}/', - values: { prop, pattern }, - }) - ); - } - } else if (prop === 'targetFilePath') { - if (bytes > MAX_FILE_PATH_VALUE_LENGTH_BYTES) { - errors.push(i18n.errorValueLengthExceeded); - } - } else if (bytes > MAX_CONDITION_VALUE_LENGTH_BYTES) { - errors.push(i18n.errorValueLengthExceeded); - } - }); + if (stringValueErrors.length > 0) { + errors.push(...stringValueErrors); + } if (errors.length) { errorMap[prop] = errors; diff --git a/x-pack/plugins/cloud_defend/public/components/control_settings/index.tsx b/x-pack/plugins/cloud_defend/public/components/control_settings/index.tsx index b673d745c4935..0dc5d2db3deb0 100644 --- a/x-pack/plugins/cloud_defend/public/components/control_settings/index.tsx +++ b/x-pack/plugins/cloud_defend/public/components/control_settings/index.tsx @@ -74,7 +74,6 @@ export const ControlSettings = ({ policy, onChange }: SettingsDeps) => { - {/** general view removed from DOM for performance and to avoid errors when invalid yaml is passed to it**/} {isGeneralViewSelected && ( { onChange={onGeneralChanges} /> )} - {/** Yaml view is kept in the dom at all times to prevent some sizing/rendering issues. - Also only listening for changes if yaml view visible to avoid isValid race condition **/} - + {isYamlViewSelected && ( + + )} ); diff --git a/x-pack/plugins/cloud_defend/public/components/control_yaml_view/index.test.tsx b/x-pack/plugins/cloud_defend/public/components/control_yaml_view/index.test.tsx index 7f48eafe2bc43..c4471e1985bba 100644 --- a/x-pack/plugins/cloud_defend/public/components/control_yaml_view/index.test.tsx +++ b/x-pack/plugins/cloud_defend/public/components/control_yaml_view/index.test.tsx @@ -8,8 +8,16 @@ import React from 'react'; import { render } from '@testing-library/react'; import '@kbn/kibana-react-plugin/public/code_editor/code_editor.test.helpers'; import { TestProvider } from '../../test/test_provider'; -import { getCloudDefendNewPolicyMock, MOCK_YAML_INVALID_CONFIGURATION } from '../../test/mocks'; +import { + getCloudDefendNewPolicyMock, + MOCK_YAML_INVALID_CONFIGURATION, + MOCK_YAML_INVALID_ACTIONS, + MOCK_YAML_TOO_MANY_FILE_SELECTORS_RESPONSES, + MOCK_YAML_INVALID_STRING_ARRAY_CONDITION, +} from '../../test/mocks'; import { ControlYamlView } from '.'; +import * as i18n from './translations'; +import { MAX_SELECTORS_AND_RESPONSES_PER_TYPE } from '../../common/constants'; describe('', () => { const onChange = jest.fn(); @@ -31,4 +39,39 @@ describe('', () => { ); }); + + it('handles additionalErrors: max selectors+responses exceeded ', async () => { + const { getByText, getByTestId } = render( + + ); + + expect(getByTestId('cloudDefendAdditionalErrors')).toBeTruthy(); + expect( + getByText( + `You cannot exceed ${MAX_SELECTORS_AND_RESPONSES_PER_TYPE} selectors + responses for a given type e.g file, process` + ) + ).toBeTruthy(); + }); + + it('handles additionalErrors: block action error', async () => { + const { getByText, getByTestId } = render( + + ); + + expect(getByTestId('cloudDefendAdditionalErrors')).toBeTruthy(); + expect(getByText(i18n.errorAlertActionRequired)).toBeTruthy(); + }); + + it('handles additionalErrors: selector condition value byte length', async () => { + const { getByText, getByTestId } = render( + + ); + + expect(getByTestId('cloudDefendAdditionalErrors')).toBeTruthy(); + expect(getByText('"sessionLeaderName" values cannot exceed 16 bytes')).toBeTruthy(); + }); }); diff --git a/x-pack/plugins/cloud_defend/public/components/control_yaml_view/index.tsx b/x-pack/plugins/cloud_defend/public/components/control_yaml_view/index.tsx index bd6e964faab94..011ffd95ba4cd 100644 --- a/x-pack/plugins/cloud_defend/public/components/control_yaml_view/index.tsx +++ b/x-pack/plugins/cloud_defend/public/components/control_yaml_view/index.tsx @@ -8,36 +8,78 @@ import React, { useCallback, useEffect, useState } from 'react'; import { EuiSpacer, EuiText, EuiFlexGroup, EuiFlexItem, EuiForm } from '@elastic/eui'; import { CodeEditor, YamlLang } from '@kbn/kibana-react-plugin/public'; import { monaco } from '@kbn/monaco'; -import yaml from 'js-yaml'; +import { uniq } from 'lodash'; import { INPUT_CONTROL } from '../../../common/constants'; import { useStyles } from './styles'; import { useConfigModel } from './hooks/use_config_model'; -import { getInputFromPolicy } from '../../common/utils'; +import { + getInputFromPolicy, + validateStringValuesForCondition, + getSelectorsAndResponsesFromYaml, + validateMaxSelectorsAndResponses, +} from '../../common/utils'; import * as i18n from './translations'; -import { ViewDeps } from '../../types'; +import { ViewDeps, SelectorConditionsMap, SelectorCondition } from '../../types'; const { editor } = monaco; const TEXT_EDITOR_PADDING = 10; -interface ConfigError { +interface EditorError { line: number; message: string; } export const ControlYamlView = ({ policy, onChange, show }: ViewDeps) => { const styles = useStyles(); - const [errors, setErrors] = useState([]); - const [actionsValid, setActionsValid] = useState(true); + const [editorErrors, setEditorErrors] = useState([]); + const [additionalErrors, setAdditionalErrors] = useState([]); const input = getInputFromPolicy(policy, INPUT_CONTROL); const configuration = input?.vars?.configuration?.value || ''; const currentModel = useConfigModel(configuration); + // not all validations can be done via json-schema + const validateAdditional = useCallback((value) => { + const errors: string[] = []; + + const { selectors, responses } = getSelectorsAndResponsesFromYaml(value); + + errors.push(...validateMaxSelectorsAndResponses(selectors, responses)); + + // validate selectors + selectors.forEach((selector) => { + Object.keys(selector).map((prop) => { + const condition = prop as SelectorCondition; + + if (SelectorConditionsMap[condition]?.type === 'stringArray') { + const values = selector[condition] as string[]; + errors.push(...validateStringValuesForCondition(condition, values)); + } + }); + }); + + // validate responses + responses.forEach((response) => { + // for now we force 'alert' action if 'block' action added. + if (response.actions.includes('block') && !response.actions.includes('alert')) { + errors.push(i18n.errorAlertActionRequired); + } + }); + + return uniq(errors); + }, []); + useEffect(() => { + // for on mount + const otherErrors = validateAdditional(configuration); + if (otherErrors.length !== additionalErrors.length) { + setAdditionalErrors(otherErrors); + } + const listener = editor.onDidChangeMarkers(([resource]) => { const markers = editor.getModelMarkers({ resource }); const errs = markers.map((marker) => { - const error: ConfigError = { + const error: EditorError = { line: marker.startLineNumber, message: marker.message, }; @@ -46,49 +88,38 @@ export const ControlYamlView = ({ policy, onChange, show }: ViewDeps) => { }); // prevents infinite loop - if (JSON.stringify(errs) !== JSON.stringify(errors)) { - onChange({ isValid: actionsValid && errs.length === 0, updatedPolicy: policy }); - setErrors(errs); + if ( + otherErrors.length !== additionalErrors.length || + JSON.stringify(errs) !== JSON.stringify(editorErrors) + ) { + onChange({ + isValid: otherErrors.length === 0 && errs.length === 0, + updatedPolicy: policy, + }); + setEditorErrors(errs); } }); return () => { listener.dispose(); }; - }, [actionsValid, errors, onChange, policy]); - - // for now we force 'alert' action on all responses. This restriction may be removed in future when we have a plan to record all responses. e.g. audit - const validateActions = useCallback((value) => { - try { - const json = yaml.load(value); - - for (let i = 0; i < json.responses.length; i++) { - const response = json.responses[i]; - - if (!response.actions.includes('alert')) { - return false; - } - } - } catch { - // noop - } - - return true; - }, []); + }, [editorErrors, onChange, policy, additionalErrors.length, validateAdditional, configuration]); const onYamlChange = useCallback( (value) => { if (input?.vars) { input.vars.configuration.value = value; - const areActionsValid = validateActions(value); - - setActionsValid(areActionsValid); + const errs = validateAdditional(value); + setAdditionalErrors(errs); - onChange({ isValid: areActionsValid && errors.length === 0, updatedPolicy: policy }); + onChange({ + isValid: errs.length === 0 && editorErrors.length === 0, + updatedPolicy: policy, + }); } }, - [errors.length, input?.vars, onChange, policy, validateActions] + [editorErrors.length, input?.vars, onChange, policy, validateAdditional] ); return ( @@ -98,7 +129,13 @@ export const ControlYamlView = ({ policy, onChange, show }: ViewDeps) => { {i18n.controlYamlHelp} - {!actionsValid && } + {additionalErrors.length > 0 && ( + + )}
{ + return ` - match: [default] + actions: [alert] +`; + }) + .join('')} +`; + export const getCloudDefendNewPolicyMock = (yaml = MOCK_YAML_CONFIGURATION): NewPackagePolicy => ({ name: 'some-cloud_defend-policy', description: '', diff --git a/x-pack/plugins/cloud_defend/public/types.ts b/x-pack/plugins/cloud_defend/public/types.ts index 8ec6f69a4514a..7b35588d547e8 100755 --- a/x-pack/plugins/cloud_defend/public/types.ts +++ b/x-pack/plugins/cloud_defend/public/types.ts @@ -87,6 +87,7 @@ export interface SelectorConditionOptions { pattern?: string; patternError?: string; selectorType?: SelectorType; + maxValueBytes?: number; // defaults to const MAX_FILE_PATH_VALUE_LENGTH_BYTES not?: SelectorCondition[]; values?: | { @@ -131,14 +132,18 @@ export const SelectorConditionsMap: SelectorConditionsMapProps = { process: ['fork', 'exec'], }, }, - targetFilePath: { selectorType: 'file', type: 'stringArray' }, + targetFilePath: { + selectorType: 'file', + type: 'stringArray', + maxValueBytes: 255, + }, ignoreVolumeFiles: { selectorType: 'file', type: 'flag', not: ['ignoreVolumeMounts'] }, ignoreVolumeMounts: { selectorType: 'file', type: 'flag', not: ['ignoreVolumeFiles'] }, processExecutable: { selectorType: 'process', type: 'stringArray', not: ['processName'] }, processName: { selectorType: 'process', type: 'stringArray', not: ['processExecutable'] }, processUserId: { selectorType: 'process', type: 'stringArray' }, sessionLeaderInteractive: { selectorType: 'process', type: 'boolean' }, - sessionLeaderName: { selectorType: 'process', type: 'stringArray' }, + sessionLeaderName: { selectorType: 'process', type: 'stringArray', maxValueBytes: 16 }, }; export type ResponseAction = 'log' | 'alert' | 'block'; @@ -146,6 +151,7 @@ export type ResponseAction = 'log' | 'alert' | 'block'; export interface Selector { name: string; operation?: string[]; + containerImageFullName?: string[]; containerImageName?: string[]; containerImageTag?: string[]; kubernetesClusterId?: string[]; diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 87b1e4e65f9c3..c7e399e6ed9ca 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -38070,7 +38070,6 @@ "xpack.cloudDefend.errorConditionRequired": "Au moins une condition par sélecteur est requise.", "xpack.cloudDefend.errorDuplicateName": "Ce nom est déjà utilisé par un autre sélecteur.", "xpack.cloudDefend.errorInvalidName": "Les noms des sélecteurs doivent être alphanumériques et ne doivent pas inclure d'espaces.", - "xpack.cloudDefend.errorValueLengthExceeded": "Les valeurs ne doivent pas dépasser 32 caractères.", "xpack.cloudDefend.errorValueRequired": "Au moins une valeur est requise.", "xpack.cloudDefend.name": "Nom", "xpack.cloudLinks.deploymentLinkLabel": "Gérer ce déploiement", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index b36c94f8422d0..4e97d9a007e22 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -38038,7 +38038,6 @@ "xpack.cloudDefend.errorConditionRequired": "セレクターにつき1つ以上の条件が必要です。", "xpack.cloudDefend.errorDuplicateName": "この名前はすでに別のセレクターで使用されています。", "xpack.cloudDefend.errorInvalidName": "セレクター名は英数字でなければならず、スペースは使用できません。", - "xpack.cloudDefend.errorValueLengthExceeded": "値は32文字以下でなければなりません。", "xpack.cloudDefend.errorValueRequired": "1つ以上の値が必要です。", "xpack.cloudDefend.name": "名前", "xpack.cloudLinks.deploymentLinkLabel": "このデプロイの管理", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index edcd2a3a084fb..5ac1921894867 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -38065,7 +38065,6 @@ "xpack.cloudDefend.errorConditionRequired": "每个选择器至少需要一个条件。", "xpack.cloudDefend.errorDuplicateName": "此名称已由其他选择器使用。", "xpack.cloudDefend.errorInvalidName": "选择器名称必须为字母数字,并且不包含空格。", - "xpack.cloudDefend.errorValueLengthExceeded": "值不能超过 32 个字符。", "xpack.cloudDefend.errorValueRequired": "至少需要一个值。", "xpack.cloudDefend.name": "名称", "xpack.cloudLinks.deploymentLinkLabel": "管理此部署", From ddd44b859bed72608729a17362d8909853a939bb Mon Sep 17 00:00:00 2001 From: Hannah Mudge Date: Tue, 11 Apr 2023 11:51:31 -0600 Subject: [PATCH 03/23] [Dashboard] Fix unsaved changes badge React error (#154607) ## Summary ### Before Since adding the tooltip to the unsaved changes badge in https://github.com/elastic/kibana/pull/154253, React was throwing an error to the console because the element in the top nav no longer had a unique key: https://user-images.githubusercontent.com/8698078/230927494-7cc931f8-68c6-4904-b99e-99b1b2872f94.mov
![image](https://user-images.githubusercontent.com/8698078/230925422-32f8ea9d-8c22-470e-a94e-0aa9eda0b4de.png) ### After This PR fixes this by adding the key **to the tooltip** if the badge has one; if it doesn't have a tooltip, then the key is added directly to the `EuiBadge` as expected. It also ensures that the tooltip has the proper a11y support (cc @elastic/kibana-accessibility) by adding the badge to the tab order and using the pass-through-props to ensure that the tooltip shows up on focus: https://user-images.githubusercontent.com/8698078/230929396-5a423c18-4a5f-410c-a3d3-9005022f8060.mov ### Checklist - [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) ### 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) --- .../public/top_nav_menu/top_nav_menu.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx index 191682818df3c..b74a8b64e8ee3 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx @@ -82,12 +82,20 @@ export function TopNavMenu( } function createBadge({ badgeText, toolTipProps, ...badgeProps }: Badge, i: number): ReactElement { - const badge = ( - + const Badge = ({ key, ...rest }: { key?: string }) => ( + {badgeText} ); - return toolTipProps ? {badge} : badge; + + const key = `nav-menu-badge-${i}`; + return toolTipProps ? ( + + + + ) : ( + + ); } function renderBadges(): ReactElement | null { From ab277e4cb48fab55f849565fb12c4d9972de3bde Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 11 Apr 2023 20:24:27 +0200 Subject: [PATCH 04/23] [ML] Explain Log Rate Spikes: Support to filter fields from grouping (#153864) - Adds a `Filter fields` popover selector inspired by EUI's data grid column picker to toggle inclusion of fields into grouping. - Moves the `Group results` switch and the `Filter fields` popover on the same level as the progress controls. - Adapts the `explain_log_rate_spikes` API endpoint to support retrieving a grouping update only. - Hides the pagination footer for the results tables if there's less results than the current page size. --- .../progress_controls/progress_controls.tsx | 15 +- .../artificial_logs/significant_terms.ts | 46 ++-- .../api/explain_log_rate_spikes/actions.ts | 10 + .../api/explain_log_rate_spikes/index.ts | 1 + .../api/explain_log_rate_spikes/schema.ts | 1 + .../aiops/common/api/stream_reducer.test.ts | 27 ++- .../aiops/common/api/stream_reducer.ts | 2 + .../explain_log_rate_spikes_analysis.tsx | 89 +++++-- .../field_filter_apply_button.tsx | 48 ++++ .../field_filter_popover.tsx | 225 ++++++++++++++++++ .../spike_analysis_table.tsx | 2 +- .../spike_analysis_table_groups.tsx | 2 +- .../server/routes/explain_log_rate_spikes.ts | 12 +- .../queries/fetch_frequent_item_sets.test.ts | 14 +- .../get_missing_significant_terms.test.ts | 30 +-- ...ransform_significant_term_to_group.test.ts | 14 +- ... explain_log_rate_spikes_full_analysis.ts} | 79 +----- .../explain_log_rate_spikes_groups_only.ts | 224 +++++++++++++++++ .../aiops/explain_log_rate_spikes_no_index.ts | 62 +++++ .../test/api_integration/apis/aiops/index.ts | 4 +- .../api_integration/apis/aiops/test_data.ts | 30 ++- .../test/api_integration/apis/aiops/types.ts | 2 + .../apps/aiops/explain_log_rate_spikes.ts | 26 ++ .../test/functional/apps/aiops/test_data.ts | 10 + x-pack/test/functional/apps/aiops/types.ts | 4 + .../aiops/explain_log_rate_spikes_page.ts | 71 ++++++ 26 files changed, 883 insertions(+), 167 deletions(-) create mode 100644 x-pack/plugins/aiops/public/components/explain_log_rate_spikes/field_filter_apply_button.tsx create mode 100644 x-pack/plugins/aiops/public/components/explain_log_rate_spikes/field_filter_popover.tsx rename x-pack/test/api_integration/apis/aiops/{explain_log_rate_spikes.ts => explain_log_rate_spikes_full_analysis.ts} (75%) create mode 100644 x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes_groups_only.ts create mode 100644 x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes_no_index.ts diff --git a/x-pack/packages/ml/aiops_components/src/progress_controls/progress_controls.tsx b/x-pack/packages/ml/aiops_components/src/progress_controls/progress_controls.tsx index 52d45da53459c..733f61f5b1b16 100644 --- a/x-pack/packages/ml/aiops_components/src/progress_controls/progress_controls.tsx +++ b/x-pack/packages/ml/aiops_components/src/progress_controls/progress_controls.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { type FC } from 'react'; import { useEuiTheme, @@ -34,19 +34,20 @@ interface ProgressControlProps { shouldRerunAnalysis: boolean; } -export function ProgressControls({ +export const ProgressControls: FC = ({ + children, progress, progressMessage, onRefresh, onCancel, isRunning, shouldRerunAnalysis, -}: ProgressControlProps) { +}) => { const { euiTheme } = useEuiTheme(); const runningProgressBarStyles = useAnimatedProgressBarBackground(euiTheme.colors.success); return ( - + @@ -78,6 +79,7 @@ export function ProgressControls({ size="s" onClick={onRefresh} color={shouldRerunAnalysis ? 'warning' : 'primary'} + fill > @@ -105,11 +107,12 @@ export function ProgressControls({ )} {isRunning && ( - + )} + {children} ); -} +}; diff --git a/x-pack/plugins/aiops/common/__mocks__/artificial_logs/significant_terms.ts b/x-pack/plugins/aiops/common/__mocks__/artificial_logs/significant_terms.ts index b1ce53a7df087..1c71932496d78 100644 --- a/x-pack/plugins/aiops/common/__mocks__/artificial_logs/significant_terms.ts +++ b/x-pack/plugins/aiops/common/__mocks__/artificial_logs/significant_terms.ts @@ -6,48 +6,48 @@ */ export const significantTerms = [ + { + fieldName: 'user', + fieldValue: 'Peter', + doc_count: 1981, + bg_count: 553, + total_doc_count: 4669, + total_bg_count: 1975, + score: 47.38899434932384, + pValue: 2.62555579103777e-21, + normalizedScore: 0.8328439168064725, + }, { fieldName: 'response_code', fieldValue: '500', doc_count: 1819, bg_count: 553, - total_doc_count: 4671, + total_doc_count: 4669, total_bg_count: 1975, - score: 26.546201745993947, - pValue: 2.9589053032077285e-12, - normalizedScore: 0.7814127409489161, + score: 26.347710713220195, + pValue: 3.6085657805889595e-12, + normalizedScore: 0.7809229492301661, }, { fieldName: 'url', fieldValue: 'home.php', doc_count: 1744, bg_count: 632, - total_doc_count: 4671, + total_doc_count: 4669, total_bg_count: 1975, - score: 4.53094842981472, - pValue: 0.010770456205312423, - normalizedScore: 0.10333028878375965, + score: 4.631197208465419, + pValue: 0.00974308761016614, + normalizedScore: 0.12006631193078789, }, { fieldName: 'url', fieldValue: 'login.php', doc_count: 1738, bg_count: 632, - total_doc_count: 4671, - total_bg_count: 1975, - score: 4.53094842981472, - pValue: 0.010770456205312423, - normalizedScore: 0.10333028878375965, - }, - { - fieldName: 'user', - fieldValue: 'Peter', - doc_count: 1981, - bg_count: 553, - total_doc_count: 4671, + total_doc_count: 4669, total_bg_count: 1975, - score: 47.34435085428873, - pValue: 2.7454255728359757e-21, - normalizedScore: 0.8327337555873047, + score: 4.359614926663956, + pValue: 0.012783309213417932, + normalizedScore: 0.07472703283204607, }, ]; diff --git a/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/actions.ts b/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/actions.ts index cbd2050a5ba8f..79a80c0040e2f 100644 --- a/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/actions.ts +++ b/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/actions.ts @@ -21,6 +21,7 @@ export const API_ACTION_NAME = { PING: 'ping', RESET_ALL: 'reset_all', RESET_ERRORS: 'reset_errors', + RESET_GROUPS: 'reset_groups', UPDATE_LOADING_STATE: 'update_loading_state', } as const; export type ApiActionName = typeof API_ACTION_NAME[keyof typeof API_ACTION_NAME]; @@ -119,6 +120,14 @@ export function resetAllAction(): ApiActionResetAll { return { type: API_ACTION_NAME.RESET_ALL }; } +interface ApiActionResetGroups { + type: typeof API_ACTION_NAME.RESET_GROUPS; +} + +export function resetGroupsAction(): ApiActionResetGroups { + return { type: API_ACTION_NAME.RESET_GROUPS }; +} + interface ApiActionUpdateLoadingState { type: typeof API_ACTION_NAME.UPDATE_LOADING_STATE; payload: { @@ -148,4 +157,5 @@ export type AiopsExplainLogRateSpikesApiAction = | ApiActionPing | ApiActionResetAll | ApiActionResetErrors + | ApiActionResetGroups | ApiActionUpdateLoadingState; diff --git a/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/index.ts b/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/index.ts index 87bcea25810dc..52e26a534baa9 100644 --- a/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/index.ts +++ b/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/index.ts @@ -14,6 +14,7 @@ export { pingAction, resetAllAction, resetErrorsAction, + resetGroupsAction, updateLoadingStateAction, API_ACTION_NAME, } from './actions'; diff --git a/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/schema.ts b/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/schema.ts index c79619170d48e..2f1bd9dbf9e24 100644 --- a/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/schema.ts +++ b/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/schema.ts @@ -31,6 +31,7 @@ export const aiopsExplainLogRateSpikesSchema = schema.object({ remainingFieldCandidates: schema.maybe(schema.arrayOf(schema.string())), // TODO Improve schema significantTerms: schema.maybe(schema.arrayOf(schema.any())), + regroupOnly: schema.maybe(schema.boolean()), }) ), /** Probability used for the random sampler aggregations */ diff --git a/x-pack/plugins/aiops/common/api/stream_reducer.test.ts b/x-pack/plugins/aiops/common/api/stream_reducer.test.ts index 3ea239b79ee2e..710f575242b74 100644 --- a/x-pack/plugins/aiops/common/api/stream_reducer.test.ts +++ b/x-pack/plugins/aiops/common/api/stream_reducer.test.ts @@ -5,9 +5,14 @@ * 2.0. */ +import { significantTerms } from '../__mocks__/artificial_logs/significant_terms'; +import { finalSignificantTermGroups } from '../__mocks__/artificial_logs/final_significant_term_groups'; + import { addSignificantTermsAction, + addSignificantTermsGroupAction, resetAllAction, + resetGroupsAction, updateLoadingStateAction, } from './explain_log_rate_spikes'; import { initialState, streamReducer } from './stream_reducer'; @@ -29,7 +34,7 @@ describe('streamReducer', () => { }); }); - it('adds significant term, then resets state again', () => { + it('adds significant term, then resets all state again', () => { const state1 = streamReducer( initialState, addSignificantTermsAction([ @@ -53,4 +58,24 @@ describe('streamReducer', () => { expect(state2.significantTerms).toHaveLength(0); }); + + it('adds significant terms and groups, then resets groups only', () => { + const state1 = streamReducer(initialState, addSignificantTermsAction(significantTerms)); + + expect(state1.significantTerms).toHaveLength(4); + expect(state1.significantTermsGroups).toHaveLength(0); + + const state2 = streamReducer( + state1, + addSignificantTermsGroupAction(finalSignificantTermGroups) + ); + + expect(state2.significantTerms).toHaveLength(4); + expect(state2.significantTermsGroups).toHaveLength(4); + + const state3 = streamReducer(state2, resetGroupsAction()); + + expect(state3.significantTerms).toHaveLength(4); + expect(state3.significantTermsGroups).toHaveLength(0); + }); }); diff --git a/x-pack/plugins/aiops/common/api/stream_reducer.ts b/x-pack/plugins/aiops/common/api/stream_reducer.ts index 7043752abd8f1..c78c94987e0ad 100644 --- a/x-pack/plugins/aiops/common/api/stream_reducer.ts +++ b/x-pack/plugins/aiops/common/api/stream_reducer.ts @@ -66,6 +66,8 @@ export function streamReducer( return { ...state, errors: [...state.errors, action.payload] }; case API_ACTION_NAME.RESET_ERRORS: return { ...state, errors: [] }; + case API_ACTION_NAME.RESET_GROUPS: + return { ...state, significantTermsGroups: [] }; case API_ACTION_NAME.RESET_ALL: return initialState; case API_ACTION_NAME.UPDATE_LOADING_STATE: diff --git a/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx index 3b0220d2331f4..f1bcdb18fbaec 100644 --- a/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx +++ b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx @@ -5,13 +5,14 @@ * 2.0. */ -import React, { useEffect, useMemo, useState, FC } from 'react'; -import { isEqual } from 'lodash'; +import React, { useEffect, useMemo, useState, type FC } from 'react'; +import { isEqual, uniq } from 'lodash'; import { EuiButton, EuiCallOut, EuiEmptyPrompt, + EuiFlexItem, EuiFormRow, EuiSpacer, EuiSwitch, @@ -38,6 +39,8 @@ import { import {} from '../spike_analysis_table'; import { useSpikeAnalysisTableRowContext } from '../spike_analysis_table/spike_analysis_table_row_provider'; +import { FieldFilterPopover } from './field_filter_popover'; + const groupResultsMessage = i18n.translate( 'xpack.aiops.spikeAnalysisTable.groupedSwitchLabel.groupResults', { @@ -86,18 +89,31 @@ export const ExplainLogRateSpikesAnalysis: FC WindowParameters | undefined >(); const [groupResults, setGroupResults] = useState(false); + const [groupSkipFields, setGroupSkipFields] = useState([]); + const [uniqueFieldNames, setUniqueFieldNames] = useState([]); const [overrides, setOverrides] = useState< ApiExplainLogRateSpikes['body']['overrides'] | undefined >(undefined); const [shouldStart, setShouldStart] = useState(false); - const onSwitchToggle = (e: { target: { checked: React.SetStateAction } }) => { + const onGroupResultsToggle = (e: { target: { checked: React.SetStateAction } }) => { setGroupResults(e.target.checked); // When toggling the group switch, clear all row selections clearAllRowState(); }; + const onFieldsFilterChange = (skippedFields: string[]) => { + setGroupSkipFields(skippedFields); + setOverrides({ + loaded: 0, + remainingFieldCandidates: [], + significantTerms: data.significantTerms.filter((d) => !skippedFields.includes(d.fieldName)), + regroupOnly: true, + }); + startHandler(true, false); + }; + const { cancel, start, @@ -122,6 +138,12 @@ export const ExplainLogRateSpikesAnalysis: FC { reducer: streamReducer, initialState } ); + const { significantTerms } = data; + useEffect( + () => setUniqueFieldNames(uniq(significantTerms.map((d) => d.fieldName)).sort()), + [significantTerms] + ); + useEffect(() => { if (!isRunning) { const { loaded, remainingFieldCandidates, groupsMissing } = data; @@ -143,14 +165,17 @@ export const ExplainLogRateSpikesAnalysis: FC // Start handler clears possibly hovered or pinned // significant terms on analysis refresh. - function startHandler(continueAnalysis = false) { + function startHandler(continueAnalysis = false, resetGroupButton = true) { if (!continueAnalysis) { setOverrides(undefined); + setUniqueFieldNames([]); } // Reset grouping to false and clear all row selections when restarting the analysis. - setGroupResults(false); - clearAllRowState(); + if (resetGroupButton) { + setGroupResults(false); + clearAllRowState(); + } setCurrentAnalysisWindowParameters(windowParameters); @@ -191,6 +216,10 @@ export const ExplainLogRateSpikesAnalysis: FC }, 0); const foundGroups = groupTableItems.length > 0 && groupItemCount > 0; + // Disable the grouping switch toggle only if no groups were found, + // the toggle wasn't enabled already and no fields were selected to be skipped. + const disabledGroupResultsSwitch = !foundGroups && !groupResults && groupSkipFields.length === 0; + return (
onRefresh={() => startHandler(false)} onCancel={cancel} shouldRerunAnalysis={shouldRerunAnalysis} - /> + > + + + + + + + + + {errors.length > 0 ? ( <> @@ -239,24 +292,10 @@ export const ExplainLogRateSpikesAnalysis: FC ) : null} - {showSpikeAnalysisTable && foundGroups && ( + {showSpikeAnalysisTable && groupResults && foundGroups && ( <> - - - + {groupResults ? groupResultsHelpMessage : undefined} )} @@ -282,7 +321,7 @@ export const ExplainLogRateSpikesAnalysis: FC } /> )} - {showSpikeAnalysisTable && groupResults && foundGroups ? ( + {showSpikeAnalysisTable && groupResults ? ( dataViewId={dataView.id} /> ) : null} - {showSpikeAnalysisTable && (!groupResults || !foundGroups) ? ( + {showSpikeAnalysisTable && !groupResults ? ( void; + tooltipContent?: string; +} + +export const FieldFilterApplyButton: FC = ({ + disabled, + onClick, + tooltipContent, +}) => { + const button = ( + + + + ); + + if (tooltipContent) { + return ( + + {button} + + ); + } + + return button; +}; diff --git a/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/field_filter_popover.tsx b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/field_filter_popover.tsx new file mode 100644 index 0000000000000..38d34983db1a3 --- /dev/null +++ b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/field_filter_popover.tsx @@ -0,0 +1,225 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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, { useEffect, useMemo, useState, type ChangeEvent, type FC } from 'react'; +import { css } from '@emotion/react'; + +import { + euiYScrollWithShadows, + useEuiTheme, + EuiButton, + EuiButtonEmpty, + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiPopover, + EuiPopoverFooter, + EuiPopoverTitle, + EuiSpacer, + EuiSwitch, + EuiText, +} from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; + +import { FieldFilterApplyButton } from './field_filter_apply_button'; + +interface FieldFilterPopoverProps { + disabled?: boolean; + disabledApplyButton?: boolean; + uniqueFieldNames: string[]; + onChange: (skippedFields: string[]) => void; +} + +// This component is mostly inspired by EUI's Data Grid Column Selector +// https://github.com/elastic/eui/blob/main/src/components/datagrid/controls/column_selector.tsx +export const FieldFilterPopover: FC = ({ + disabled, + disabledApplyButton, + uniqueFieldNames, + onChange, +}) => { + const euiThemeContext = useEuiTheme(); + // Inspired by https://github.com/elastic/eui/blob/main/src/components/datagrid/controls/_data_grid_column_selector.scss + const fieldSelectPopover = useMemo( + () => css` + ${euiYScrollWithShadows(euiThemeContext, {})} + max-height: 400px; + `, + [euiThemeContext] + ); + + const [isTouched, setIsTouched] = useState(false); + const [fieldSearchText, setFieldSearchText] = useState(''); + const [skippedFields, setSkippedFields] = useState([]); + const setFieldsFilter = (fieldNames: string[], checked: boolean) => { + let updatedSkippedFields = [...skippedFields]; + if (!checked) { + updatedSkippedFields.push(...fieldNames); + } else { + updatedSkippedFields = skippedFields.filter((d) => !fieldNames.includes(d)); + } + setSkippedFields(updatedSkippedFields); + setIsTouched(true); + }; + + const [isFieldSelectionPopoverOpen, setIsFieldSelectionPopoverOpen] = useState(false); + const onFieldSelectionButtonClick = () => setIsFieldSelectionPopoverOpen((isOpen) => !isOpen); + const closePopover = () => setIsFieldSelectionPopoverOpen(false); + + const filteredUniqueFieldNames = useMemo(() => { + return uniqueFieldNames.filter( + (d) => d.toLowerCase().indexOf(fieldSearchText.toLowerCase()) !== -1 + ); + }, [fieldSearchText, uniqueFieldNames]); + + // If the supplied list of unique field names changes, do a sanity check to only + // keep field names in the list of skipped fields that still are in the list of unique fields. + useEffect(() => { + setSkippedFields((previousSkippedFields) => + previousSkippedFields.filter((d) => uniqueFieldNames.includes(d)) + ); + }, [uniqueFieldNames]); + + const selectedFieldCount = uniqueFieldNames.length - skippedFields.length; + + return ( + + + + } + isOpen={isFieldSelectionPopoverOpen} + closePopover={closePopover} + > + + + + + + ) => setFieldSearchText(e.currentTarget.value)} + data-test-subj="aiopsFieldSelectorSearch" + /> + +
+ {filteredUniqueFieldNames.map((fieldName) => ( +
+ setFieldsFilter([fieldName], e.target.checked)} + checked={!skippedFields.includes(fieldName)} + /> +
+ ))} +
+ + + <> + + setFieldsFilter(filteredUniqueFieldNames, true)} + disabled={fieldSearchText.length > 0 && filteredUniqueFieldNames.length === 0} + data-test-subj="aiopsFieldSelectorSelectAllFieldsButton" + > + {fieldSearchText.length > 0 ? ( + + ) : ( + + )} + + + + setFieldsFilter(filteredUniqueFieldNames, false)} + disabled={fieldSearchText.length > 0 && filteredUniqueFieldNames.length === 0} + data-test-subj="aiopsFieldSelectorDeselectAllFieldsButton" + > + {fieldSearchText.length > 0 ? ( + + ) : ( + + )} + + + + + { + onChange(skippedFields); + setFieldSearchText(''); + setIsFieldSelectionPopoverOpen(false); + closePopover(); + }} + disabled={disabledApplyButton || selectedFieldCount < 2 || !isTouched} + tooltipContent={ + selectedFieldCount < 2 + ? i18n.translate('xpack.aiops.analysis.fieldSelectorNotEnoughFieldsSelected', { + defaultMessage: 'Grouping requires at least 2 fields to be selected.', + }) + : undefined + } + /> + + + +
+ ); +}; diff --git a/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table.tsx b/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table.tsx index 619cd11ea757f..b670a42c45a3b 100644 --- a/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table.tsx +++ b/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table.tsx @@ -395,7 +395,7 @@ export const SpikeAnalysisTable: FC = ({ columns={columns} items={pageOfItems} onChange={onChange} - pagination={pagination} + pagination={pagination.totalItemCount > pagination.pageSize ? pagination : undefined} loading={false} sorting={sorting as EuiTableSortingType} rowProps={(significantTerm) => { diff --git a/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table_groups.tsx b/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table_groups.tsx index 9f4aa2a148d76..20be12531e53a 100644 --- a/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table_groups.tsx +++ b/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table_groups.tsx @@ -502,7 +502,7 @@ export const SpikeAnalysisGroupsTable: FC = ({ itemId="id" itemIdToExpandedRowMap={itemIdToExpandedRowMap} onChange={onChange} - pagination={pagination} + pagination={pagination.totalItemCount > pagination.pageSize ? pagination : undefined} loading={false} sorting={sorting as EuiTableSortingType} rowProps={(group) => { diff --git a/x-pack/plugins/aiops/server/routes/explain_log_rate_spikes.ts b/x-pack/plugins/aiops/server/routes/explain_log_rate_spikes.ts index 9cbad394d548b..787071d1e33d8 100644 --- a/x-pack/plugins/aiops/server/routes/explain_log_rate_spikes.ts +++ b/x-pack/plugins/aiops/server/routes/explain_log_rate_spikes.ts @@ -35,6 +35,7 @@ import { pingAction, resetAllAction, resetErrorsAction, + resetGroupsAction, updateLoadingStateAction, AiopsExplainLogRateSpikesApiAction, } from '../../common/api/explain_log_rate_spikes'; @@ -178,6 +179,11 @@ export const defineExplainLogRateSpikesRoute = ( push(resetErrorsAction()); } + if (request.body.overrides?.regroupOnly) { + logDebugMessage('Reset Groups.'); + push(resetGroupsAction()); + } + if (request.body.overrides?.loaded) { logDebugMessage(`Set 'loaded' override to '${request.body.overrides?.loaded}'.`); loaded = request.body.overrides?.loaded; @@ -571,7 +577,11 @@ export const defineExplainLogRateSpikesRoute = ( logDebugMessage(`Fetch ${significantTerms.length} field/value histograms.`); // time series filtered by fields - if (significantTerms.length > 0 && overallTimeSeries !== undefined) { + if ( + significantTerms.length > 0 && + overallTimeSeries !== undefined && + !request.body.overrides?.regroupOnly + ) { const fieldValueHistogramQueue = queue(async function (cp: SignificantTerm) { if (shouldStop) { logDebugMessage('shouldStop abort fetching field/value histograms.'); diff --git a/x-pack/plugins/aiops/server/routes/queries/fetch_frequent_item_sets.test.ts b/x-pack/plugins/aiops/server/routes/queries/fetch_frequent_item_sets.test.ts index 142a04ed1b373..e2dbeb781b999 100644 --- a/x-pack/plugins/aiops/server/routes/queries/fetch_frequent_item_sets.test.ts +++ b/x-pack/plugins/aiops/server/routes/queries/fetch_frequent_item_sets.test.ts @@ -16,17 +16,17 @@ describe('getShouldClauses', () => { expect(shouldClauses).toEqual([ { terms: { - response_code: ['500'], + user: ['Peter'], }, }, { terms: { - url: ['home.php', 'login.php'], + response_code: ['500'], }, }, { terms: { - user: ['Peter'], + url: ['home.php', 'login.php'], }, }, ]); @@ -38,6 +38,10 @@ describe('getFrequentItemSetsAggFields', () => { const frequentItemSetsAggFields = getFrequentItemSetsAggFields(significantTerms); expect(frequentItemSetsAggFields).toEqual([ + { + field: 'user', + include: ['Peter'], + }, { field: 'response_code', include: ['500'], @@ -46,10 +50,6 @@ describe('getFrequentItemSetsAggFields', () => { field: 'url', include: ['home.php', 'login.php'], }, - { - field: 'user', - include: ['Peter'], - }, ]); }); }); diff --git a/x-pack/plugins/aiops/server/routes/queries/get_missing_significant_terms.test.ts b/x-pack/plugins/aiops/server/routes/queries/get_missing_significant_terms.test.ts index a41f92511e361..5da659dd58631 100644 --- a/x-pack/plugins/aiops/server/routes/queries/get_missing_significant_terms.test.ts +++ b/x-pack/plugins/aiops/server/routes/queries/get_missing_significant_terms.test.ts @@ -34,27 +34,27 @@ describe('getMissingSignificantTerms', () => { ); expect(missingSignificantTerms).toEqual([ - { - bg_count: 632, - doc_count: 1738, - fieldName: 'url', - fieldValue: 'login.php', - normalizedScore: 0.10333028878375965, - pValue: 0.010770456205312423, - score: 4.53094842981472, - total_bg_count: 1975, - total_doc_count: 4671, - }, { bg_count: 553, doc_count: 1981, fieldName: 'user', fieldValue: 'Peter', - normalizedScore: 0.8327337555873047, - pValue: 2.7454255728359757e-21, - score: 47.34435085428873, + normalizedScore: 0.8328439168064725, + pValue: 2.62555579103777e-21, + score: 47.38899434932384, + total_bg_count: 1975, + total_doc_count: 4669, + }, + { + bg_count: 632, + doc_count: 1738, + fieldName: 'url', + fieldValue: 'login.php', + normalizedScore: 0.07472703283204607, + pValue: 0.012783309213417932, + score: 4.359614926663956, total_bg_count: 1975, - total_doc_count: 4671, + total_doc_count: 4669, }, ]); }); diff --git a/x-pack/plugins/aiops/server/routes/queries/transform_significant_term_to_group.test.ts b/x-pack/plugins/aiops/server/routes/queries/transform_significant_term_to_group.test.ts index f3b691f8c4bfb..ec86dbb47d81e 100644 --- a/x-pack/plugins/aiops/server/routes/queries/transform_significant_term_to_group.test.ts +++ b/x-pack/plugins/aiops/server/routes/queries/transform_significant_term_to_group.test.ts @@ -40,18 +40,18 @@ describe('getMissingSignificantTerms', () => { ); expect(transformed).toEqual({ - docCount: 1738, + docCount: 1981, group: [ { + docCount: 1981, duplicate: 1, - fieldName: 'url', - fieldValue: 'login.php', - docCount: 1738, - pValue: 0.010770456205312423, + fieldName: 'user', + fieldValue: 'Peter', + pValue: 2.62555579103777e-21, }, ], - id: '368426784', - pValue: 0.010770456205312423, + id: '817080373', + pValue: 2.62555579103777e-21, }); }); }); diff --git a/x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes.ts b/x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes_full_analysis.ts similarity index 75% rename from x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes.ts rename to x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes_full_analysis.ts index d2bf38ca8532c..5b48214d39bbd 100644 --- a/x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes.ts +++ b/x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes_full_analysis.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { sortBy } from 'lodash'; +import { orderBy } from 'lodash'; import fetch from 'node-fetch'; import { format as formatUrl } from 'url'; @@ -25,7 +25,7 @@ export default ({ getService }: FtrProviderContext) => { const kibanaServerUrl = formatUrl(config.get('servers.kibana')); const esArchiver = getService('esArchiver'); - describe('POST /internal/aiops/explain_log_rate_spikes', () => { + describe('POST /internal/aiops/explain_log_rate_spikes - full analysis', () => { explainLogRateSpikesTestData.forEach((testData) => { describe(`with ${testData.testName}`, () => { before(async () => { @@ -60,29 +60,16 @@ export default ({ getService }: FtrProviderContext) => { ); expect(addSignificantTermsActions.length).to.greaterThan(0); - const significantTerms = addSignificantTermsActions - .flatMap((d) => d.payload) - .sort(function (a, b) { - if (a.fieldName === b.fieldName) { - return b.fieldValue - a.fieldValue; - } - return a.fieldName > b.fieldName ? 1 : -1; - }); - - expect(significantTerms.length).to.eql( - testData.expected.significantTerms.length, - `Expected 'significantTerms.length' to be ${testData.expected.significantTerms.length}, got ${significantTerms.length}.` + const significantTerms = orderBy( + addSignificantTermsActions.flatMap((d) => d.payload), + ['doc_count'], + ['desc'] + ); + + expect(significantTerms).to.eql( + testData.expected.significantTerms, + 'Significant terms do not match expected values.' ); - significantTerms.forEach((cp, index) => { - const ecp = testData.expected.significantTerms[index]; - expect(cp.fieldName).to.eql(ecp.fieldName); - expect(cp.fieldValue).to.eql(ecp.fieldValue); - expect(cp.doc_count).to.eql( - ecp.doc_count, - `Expected doc_count for '${cp.fieldName}:${cp.fieldValue}' to be ${ecp.doc_count}, got ${cp.doc_count}` - ); - expect(cp.bg_count).to.eql(ecp.bg_count); - }); const histogramActions = data.filter((d) => d.type === testData.expected.histogramFilter); const histograms = histogramActions.flatMap((d) => d.payload); @@ -96,8 +83,8 @@ export default ({ getService }: FtrProviderContext) => { const groupActions = data.filter((d) => d.type === testData.expected.groupFilter); const groups = groupActions.flatMap((d) => d.payload); - expect(sortBy(groups, 'id')).to.eql( - sortBy(testData.expected.groups, 'id'), + expect(orderBy(groups, ['docCount'], ['desc'])).to.eql( + orderBy(testData.expected.groups, ['docCount'], ['desc']), 'Grouping result does not match expected values.' ); @@ -230,46 +217,6 @@ export default ({ getService }: FtrProviderContext) => { flushFix: false, }); }); - - it('should return an error for non existing index without streaming', async () => { - const resp = await supertest - .post(`/internal/aiops/explain_log_rate_spikes`) - .set('kbn-xsrf', 'kibana') - .send({ - ...testData.requestBody, - index: 'does_not_exist', - }) - .expect(200); - - const chunks: string[] = resp.body.toString().split('\n'); - - expect(chunks.length).to.eql( - testData.expected.noIndexChunksLength, - `Expected 'noIndexChunksLength' to be ${testData.expected.noIndexChunksLength}, got ${chunks.length}.` - ); - - const lastChunk = chunks.pop(); - expect(lastChunk).to.be(''); - - let data: any[] = []; - - expect(() => { - data = chunks.map((c) => JSON.parse(c)); - }).not.to.throwError(); - - expect(data.length).to.eql( - testData.expected.noIndexActionsLength, - `Expected 'noIndexActionsLength' to be ${testData.expected.noIndexActionsLength}, got ${data.length}.` - ); - data.forEach((d) => { - expect(typeof d.type).to.be('string'); - }); - - const errorActions = data.filter((d) => d.type === testData.expected.errorFilter); - expect(errorActions.length).to.be(1); - - expect(errorActions[0].payload).to.be('Failed to fetch index information.'); - }); }); }); }); diff --git a/x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes_groups_only.ts b/x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes_groups_only.ts new file mode 100644 index 0000000000000..b88c07cc0df1c --- /dev/null +++ b/x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes_groups_only.ts @@ -0,0 +1,224 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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 { orderBy } from 'lodash'; +import fetch from 'node-fetch'; +import { format as formatUrl } from 'url'; + +import expect from '@kbn/expect'; + +import type { ApiExplainLogRateSpikes } from '@kbn/aiops-plugin/common/api'; + +import type { FtrProviderContext } from '../../ftr_provider_context'; + +import { parseStream } from './parse_stream'; +import { explainLogRateSpikesTestData } from './test_data'; + +export default ({ getService }: FtrProviderContext) => { + const aiops = getService('aiops'); + const supertest = getService('supertest'); + const config = getService('config'); + const kibanaServerUrl = formatUrl(config.get('servers.kibana')); + const esArchiver = getService('esArchiver'); + + describe('POST /internal/aiops/explain_log_rate_spikes - groups only', () => { + explainLogRateSpikesTestData.forEach((testData) => { + const overrides = { + loaded: 0, + remainingFieldCandidates: [], + significantTerms: testData.expected.significantTerms, + regroupOnly: true, + }; + + describe(`with ${testData.testName}`, () => { + before(async () => { + if (testData.esArchive) { + await esArchiver.loadIfNeeded(testData.esArchive); + } else if (testData.dataGenerator) { + await aiops.explainLogRateSpikesDataGenerator.generateData(testData.dataGenerator); + } + }); + + after(async () => { + if (testData.esArchive) { + await esArchiver.unload(testData.esArchive); + } else if (testData.dataGenerator) { + await aiops.explainLogRateSpikesDataGenerator.removeGeneratedData( + testData.dataGenerator + ); + } + }); + + async function assertAnalysisResult(data: any[]) { + expect(data.length).to.eql( + testData.expected.actionsLengthGroupOnly, + `Expected 'actionsLengthGroupOnly' to be ${testData.expected.actionsLengthGroupOnly}, got ${data.length}.` + ); + data.forEach((d) => { + expect(typeof d.type).to.be('string'); + }); + + const addSignificantTermsActions = data.filter( + (d) => d.type === testData.expected.significantTermFilter + ); + expect(addSignificantTermsActions.length).to.be(0); + + const histogramActions = data.filter((d) => d.type === testData.expected.histogramFilter); + // for each significant term we should get a histogram + expect(histogramActions.length).to.be(0); + + const groupActions = data.filter((d) => d.type === testData.expected.groupFilter); + const groups = groupActions.flatMap((d) => d.payload); + + expect(orderBy(groups, ['docCount'], ['desc'])).to.eql( + orderBy(testData.expected.groups, ['docCount'], ['desc']), + 'Grouping result does not match expected values.' + ); + + const groupHistogramActions = data.filter( + (d) => d.type === testData.expected.groupHistogramFilter + ); + const groupHistograms = groupHistogramActions.flatMap((d) => d.payload); + // for each significant terms group we should get a histogram + expect(groupHistograms.length).to.be(groups.length); + // each histogram should have a length of 20 items. + groupHistograms.forEach((h, index) => { + expect(h.histogram.length).to.be(20); + }); + } + + async function requestWithoutStreaming(body: ApiExplainLogRateSpikes['body']) { + const resp = await supertest + .post(`/internal/aiops/explain_log_rate_spikes`) + .set('kbn-xsrf', 'kibana') + .send(body) + .expect(200); + + // compression is on by default so if the request body is undefined + // the response header should include "gzip" and otherwise be "undefined" + if (body.compressResponse === undefined) { + expect(resp.header['content-encoding']).to.be('gzip'); + } else if (body.compressResponse === false) { + expect(resp.header['content-encoding']).to.be(undefined); + } + + expect(Buffer.isBuffer(resp.body)).to.be(true); + + const chunks: string[] = resp.body.toString().split('\n'); + + expect(chunks.length).to.eql( + testData.expected.chunksLengthGroupOnly, + `Expected 'chunksLength' to be ${testData.expected.chunksLengthGroupOnly}, got ${chunks.length}.` + ); + + const lastChunk = chunks.pop(); + expect(lastChunk).to.be(''); + + let data: any[] = []; + + expect(() => { + data = chunks.map((c) => JSON.parse(c)); + }).not.to.throwError(); + + await assertAnalysisResult(data); + } + + it('should return group only data without streaming with compression with flushFix', async () => { + await requestWithoutStreaming({ ...testData.requestBody, overrides }); + }); + + it('should return group only data without streaming with compression without flushFix', async () => { + await requestWithoutStreaming({ ...testData.requestBody, overrides, flushFix: false }); + }); + + it('should return group only data without streaming without compression with flushFix', async () => { + await requestWithoutStreaming({ + ...testData.requestBody, + overrides, + compressResponse: false, + }); + }); + + it('should return group only data without streaming without compression without flushFix', async () => { + await requestWithoutStreaming({ + ...testData.requestBody, + overrides, + compressResponse: false, + flushFix: false, + }); + }); + + async function requestWithStreaming(body: ApiExplainLogRateSpikes['body']) { + const resp = await fetch(`${kibanaServerUrl}/internal/aiops/explain_log_rate_spikes`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'kbn-xsrf': 'stream', + }, + body: JSON.stringify(body), + }); + + // compression is on by default so if the request body is undefined + // the response header should include "gzip" and otherwise be "null" + if (body.compressResponse === undefined) { + expect(resp.headers.get('content-encoding')).to.be('gzip'); + } else if (body.compressResponse === false) { + expect(resp.headers.get('content-encoding')).to.be(null); + } + + expect(resp.ok).to.be(true); + expect(resp.status).to.be(200); + + const stream = resp.body; + + expect(stream).not.to.be(null); + + if (stream !== null) { + const data: any[] = []; + let chunkCounter = 0; + const parseStreamCallback = (c: number) => (chunkCounter = c); + + for await (const action of parseStream(stream, parseStreamCallback)) { + expect(action.type).not.to.be('error'); + data.push(action); + } + + // If streaming works correctly we should receive more than one chunk. + expect(chunkCounter).to.be.greaterThan(1); + + await assertAnalysisResult(data); + } + } + + it('should return group only in chunks with streaming with compression with flushFix', async () => { + await requestWithStreaming({ ...testData.requestBody, overrides }); + }); + + it('should return group only in chunks with streaming with compression without flushFix', async () => { + await requestWithStreaming({ ...testData.requestBody, overrides, flushFix: false }); + }); + + it('should return group only in chunks with streaming without compression with flushFix', async () => { + await requestWithStreaming({ + ...testData.requestBody, + overrides, + compressResponse: false, + }); + }); + + it('should return group only in chunks with streaming without compression without flushFix', async () => { + await requestWithStreaming({ + ...testData.requestBody, + overrides, + compressResponse: false, + flushFix: false, + }); + }); + }); + }); + }); +}; diff --git a/x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes_no_index.ts b/x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes_no_index.ts new file mode 100644 index 0000000000000..fb421697a98e1 --- /dev/null +++ b/x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes_no_index.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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'; + +import { explainLogRateSpikesTestData } from './test_data'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + + describe('POST /internal/aiops/explain_log_rate_spikes - no index', () => { + explainLogRateSpikesTestData.forEach((testData) => { + describe(`with ${testData.testName}`, () => { + it('should return an error for non existing index without streaming', async () => { + const resp = await supertest + .post(`/internal/aiops/explain_log_rate_spikes`) + .set('kbn-xsrf', 'kibana') + .send({ + ...testData.requestBody, + index: 'does_not_exist', + }) + .expect(200); + + const chunks: string[] = resp.body.toString().split('\n'); + + expect(chunks.length).to.eql( + testData.expected.noIndexChunksLength, + `Expected 'noIndexChunksLength' to be ${testData.expected.noIndexChunksLength}, got ${chunks.length}.` + ); + + const lastChunk = chunks.pop(); + expect(lastChunk).to.be(''); + + let data: any[] = []; + + expect(() => { + data = chunks.map((c) => JSON.parse(c)); + }).not.to.throwError(); + + expect(data.length).to.eql( + testData.expected.noIndexActionsLength, + `Expected 'noIndexActionsLength' to be ${testData.expected.noIndexActionsLength}, got ${data.length}.` + ); + data.forEach((d) => { + expect(typeof d.type).to.be('string'); + }); + + const errorActions = data.filter((d) => d.type === testData.expected.errorFilter); + expect(errorActions.length).to.be(1); + + expect(errorActions[0].payload).to.be('Failed to fetch index information.'); + }); + }); + }); + }); +}; diff --git a/x-pack/test/api_integration/apis/aiops/index.ts b/x-pack/test/api_integration/apis/aiops/index.ts index f311f35a51f87..238484c644a28 100644 --- a/x-pack/test/api_integration/apis/aiops/index.ts +++ b/x-pack/test/api_integration/apis/aiops/index.ts @@ -14,7 +14,9 @@ export default function ({ loadTestFile }: FtrProviderContext) { this.tags(['aiops']); if (AIOPS_ENABLED) { - loadTestFile(require.resolve('./explain_log_rate_spikes')); + loadTestFile(require.resolve('./explain_log_rate_spikes_full_analysis')); + loadTestFile(require.resolve('./explain_log_rate_spikes_groups_only')); + loadTestFile(require.resolve('./explain_log_rate_spikes_no_index')); } }); } diff --git a/x-pack/test/api_integration/apis/aiops/test_data.ts b/x-pack/test/api_integration/apis/aiops/test_data.ts index 001000c29d611..b2bf31cded84a 100644 --- a/x-pack/test/api_integration/apis/aiops/test_data.ts +++ b/x-pack/test/api_integration/apis/aiops/test_data.ts @@ -31,7 +31,9 @@ export const explainLogRateSpikesTestData: TestData[] = [ }, expected: { chunksLength: 35, + chunksLengthGroupOnly: 5, actionsLength: 34, + actionsLengthGroupOnly: 4, noIndexChunksLength: 4, noIndexActionsLength: 3, significantTermFilter: 'add_significant_terms', @@ -40,27 +42,27 @@ export const explainLogRateSpikesTestData: TestData[] = [ histogramFilter: 'add_significant_terms_histogram', errorFilter: 'add_error', significantTerms: [ - { - fieldName: 'day_of_week', - fieldValue: 'Wednesday', - doc_count: 145, - bg_count: 142, - score: 36.31595998561873, - pValue: 1.6911377077437753e-16, - normalizedScore: 0.8055203624020835, - total_doc_count: 0, - total_bg_count: 0, - }, { fieldName: 'day_of_week', fieldValue: 'Thursday', doc_count: 157, bg_count: 224, + total_doc_count: 480, + total_bg_count: 1328, score: 20.366950718358762, pValue: 1.428057484826135e-9, normalizedScore: 0.7661649691018979, - total_doc_count: 0, - total_bg_count: 0, + }, + { + fieldName: 'day_of_week', + fieldValue: 'Wednesday', + doc_count: 145, + bg_count: 142, + total_doc_count: 480, + total_bg_count: 1328, + score: 36.31595998561873, + pValue: 1.6911377077437753e-16, + normalizedScore: 0.8055203624020835, }, ], groups: [], @@ -84,7 +86,9 @@ export const explainLogRateSpikesTestData: TestData[] = [ }, expected: { chunksLength: 27, + chunksLengthGroupOnly: 11, actionsLength: 26, + actionsLengthGroupOnly: 10, noIndexChunksLength: 4, noIndexActionsLength: 3, significantTermFilter: 'add_significant_terms', diff --git a/x-pack/test/api_integration/apis/aiops/types.ts b/x-pack/test/api_integration/apis/aiops/types.ts index b3c6ea166eeac..1cdd173f183f4 100644 --- a/x-pack/test/api_integration/apis/aiops/types.ts +++ b/x-pack/test/api_integration/apis/aiops/types.ts @@ -15,7 +15,9 @@ export interface TestData { requestBody: ApiExplainLogRateSpikes['body']; expected: { chunksLength: number; + chunksLengthGroupOnly: number; actionsLength: number; + actionsLengthGroupOnly: number; noIndexChunksLength: number; noIndexActionsLength: number; significantTermFilter: 'add_significant_terms'; diff --git a/x-pack/test/functional/apps/aiops/explain_log_rate_spikes.ts b/x-pack/test/functional/apps/aiops/explain_log_rate_spikes.ts index 0318805b85cad..d34169b05a408 100644 --- a/x-pack/test/functional/apps/aiops/explain_log_rate_spikes.ts +++ b/x-pack/test/functional/apps/aiops/explain_log_rate_spikes.ts @@ -162,6 +162,32 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { expect(orderBy(analysisTable, ['fieldName', 'fieldValue'])).to.be.eql( orderBy(testData.expected.analysisTable, ['fieldName', 'fieldValue']) ); + + // Assert the field selector that allows to costumize grouping + await aiops.explainLogRateSpikesPage.assertFieldFilterPopoverButtonExists(false); + await aiops.explainLogRateSpikesPage.clickFieldFilterPopoverButton(true); + await aiops.explainLogRateSpikesPage.assertFieldSelectorFieldNameList( + testData.expected.fieldSelectorPopover + ); + + // Filter fields + await aiops.explainLogRateSpikesPage.setFieldSelectorSearch(testData.fieldSelectorSearch); + await aiops.explainLogRateSpikesPage.assertFieldSelectorFieldNameList([ + testData.fieldSelectorSearch, + ]); + await aiops.explainLogRateSpikesPage.clickFieldSelectorDisableAllSelectedButton(); + await aiops.explainLogRateSpikesPage.assertFieldFilterApplyButtonExists( + !testData.fieldSelectorApplyAvailable + ); + + if (testData.fieldSelectorApplyAvailable) { + await aiops.explainLogRateSpikesPage.clickFieldFilterApplyButton(); + const filteredAnalysisGroupsTable = + await aiops.explainLogRateSpikesAnalysisGroupsTable.parseAnalysisTable(); + expect(orderBy(filteredAnalysisGroupsTable, 'group')).to.be.eql( + orderBy(testData.expected.filteredAnalysisGroupsTable, 'group') + ); + } }); } diff --git a/x-pack/test/functional/apps/aiops/test_data.ts b/x-pack/test/functional/apps/aiops/test_data.ts index ae2aeacb12dfd..1ccc441618bdb 100644 --- a/x-pack/test/functional/apps/aiops/test_data.ts +++ b/x-pack/test/functional/apps/aiops/test_data.ts @@ -15,6 +15,8 @@ export const farequoteDataViewTestData: TestData = { brushDeviationTargetTimestamp: 1455033600000, brushIntervalFactor: 1, chartClickCoordinates: [0, 0], + fieldSelectorSearch: 'airline', + fieldSelectorApplyAvailable: false, expected: { totalDocCountFormatted: '86,374', analysisGroupsTable: [ @@ -36,6 +38,7 @@ export const farequoteDataViewTestData: TestData = { impact: 'High', }, ], + fieldSelectorPopover: ['airline', 'custom_field.keyword'], }, }; @@ -54,6 +57,8 @@ export const artificialLogDataViewTestData: TestData = { brushDeviationTargetTimestamp: DEVIATION_TS + DAY_MS / 2, brushIntervalFactor: 10, chartClickCoordinates: [-200, 30], + fieldSelectorSearch: 'user', + fieldSelectorApplyAvailable: true, expected: { totalDocCountFormatted: '8,400', analysisGroupsTable: [ @@ -74,6 +79,10 @@ export const artificialLogDataViewTestData: TestData = { group: 'user: Peterurl: login.php', }, ], + filteredAnalysisGroupsTable: [ + { group: '* url: home.phpresponse_code: 500', docCount: '792' }, + { group: '* url: login.phpresponse_code: 500', docCount: '790' }, + ], analysisTable: [ { fieldName: 'response_code', @@ -90,6 +99,7 @@ export const artificialLogDataViewTestData: TestData = { pValue: '0.00974', }, ], + fieldSelectorPopover: ['response_code', 'url', 'user'], }, }; diff --git a/x-pack/test/functional/apps/aiops/types.ts b/x-pack/test/functional/apps/aiops/types.ts index a7f53f55976ea..7a758aa4a65ff 100644 --- a/x-pack/test/functional/apps/aiops/types.ts +++ b/x-pack/test/functional/apps/aiops/types.ts @@ -15,9 +15,12 @@ export interface TestData { brushDeviationTargetTimestamp: number; brushIntervalFactor: number; chartClickCoordinates: [number, number]; + fieldSelectorSearch: string; + fieldSelectorApplyAvailable: boolean; expected: { totalDocCountFormatted: string; analysisGroupsTable: Array<{ group: string; docCount: string }>; + filteredAnalysisGroupsTable?: Array<{ group: string; docCount: string }>; analysisTable: Array<{ fieldName: string; fieldValue: string; @@ -25,5 +28,6 @@ export interface TestData { pValue: string; impact: string; }>; + fieldSelectorPopover: string[]; }; } diff --git a/x-pack/test/functional/services/aiops/explain_log_rate_spikes_page.ts b/x-pack/test/functional/services/aiops/explain_log_rate_spikes_page.ts index 8c46af2076db0..3a921a74ee359 100644 --- a/x-pack/test/functional/services/aiops/explain_log_rate_spikes_page.ts +++ b/x-pack/test/functional/services/aiops/explain_log_rate_spikes_page.ts @@ -12,6 +12,7 @@ import type { FtrProviderContext } from '../../ftr_provider_context'; export function ExplainLogRateSpikesPageProvider({ getService }: FtrProviderContext) { const browser = getService('browser'); const elasticChart = getService('elasticChart'); + const ml = getService('ml'); const testSubjects = getService('testSubjects'); const retry = getService('retry'); @@ -121,6 +122,76 @@ export function ExplainLogRateSpikesPageProvider({ getService }: FtrProviderCont }); }, + async assertFieldFilterPopoverButtonExists(isOpen: boolean) { + await retry.tryForTime(5000, async () => { + await testSubjects.existOrFail('aiopsFieldFilterButton'); + + if (isOpen) { + await testSubjects.existOrFail('aiopsFieldSelectorSearch'); + } else { + await testSubjects.missingOrFail('aiopsFieldSelectorSearch'); + } + }); + }, + + async clickFieldFilterPopoverButton(expectPopoverToBeOpen: boolean) { + await testSubjects.clickWhenNotDisabledWithoutRetry('aiopsFieldFilterButton'); + + await retry.tryForTime(30 * 1000, async () => { + await this.assertFieldFilterPopoverButtonExists(expectPopoverToBeOpen); + }); + }, + + async assertFieldSelectorFieldNameList(expectedFields: string[]) { + const currentFields = await testSubjects.getVisibleText('aiopsFieldSelectorFieldNameList'); + expect(currentFields).to.be(expectedFields.join('\n')); + }, + + async setFieldSelectorSearch(searchText: string) { + await ml.commonUI.setValueWithChecks('aiopsFieldSelectorSearch', searchText, { + clearWithKeyboard: true, + enforceDataTestSubj: true, + }); + await this.assertFieldSelectorSearchValue(searchText); + }, + + async clickFieldSelectorDisableAllSelectedButton() { + await testSubjects.clickWhenNotDisabledWithoutRetry( + 'aiopsFieldSelectorDeselectAllFieldsButton' + ); + + await retry.tryForTime(30 * 1000, async () => { + await retry.tryForTime(5000, async () => { + await testSubjects.missingOrFail('aiopsFieldSelectorFieldNameListItem checked'); + }); + }); + }, + + async assertFieldSelectorSearchValue(expectedValue: string) { + const actualSearchValue = await testSubjects.getAttribute( + 'aiopsFieldSelectorSearch', + 'value' + ); + expect(actualSearchValue).to.eql( + expectedValue, + `Field selector search input text should be '${expectedValue}' (got '${actualSearchValue}')` + ); + }, + + async assertFieldFilterApplyButtonExists(disabled: boolean) { + await retry.tryForTime(5000, async () => { + await testSubjects.existOrFail(`aiopsFieldFilterApplyButton${disabled ? ' disabled' : ''}`); + }); + }, + + async clickFieldFilterApplyButton() { + await testSubjects.clickWhenNotDisabledWithoutRetry('aiopsFieldFilterApplyButton'); + + await retry.tryForTime(30 * 1000, async () => { + await this.assertFieldFilterPopoverButtonExists(false); + }); + }, + async assertRerunAnalysisButtonExists(shouldRerun: boolean) { await testSubjects.existOrFail( `aiopsRerunAnalysisButton${shouldRerun ? ' shouldRerun' : ''}` From 2636262e093f188e4937d192d302607eeaafff85 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Tue, 11 Apr 2023 11:32:05 -0700 Subject: [PATCH 05/23] [Fleet] Fix "Advanced options" toggle in policy editor always showing (#154612) ## Summary _Please review with [whitespace ignore](https://github.com/elastic/kibana/pull/154612/files?diff=unified&w=1)!_ In #143097 the conditional for showing `Advanced options` was removed as we introduced experimental indexing toggles which are always shown. However in #148418 (8.7) we put the indexing toggles behind a feature flag. This caused the `Advanced options` toggle to always be shown regardless of there is any content underneath. I spotted this while testing something unrelated. This PR fixes that by adding a condition back that is based on aggregating the conditionals of everything underneath (existence of advanced vars, whether pipelines & mappings are shown, and if experimental indexing toggles are enabled). --- .../package_policy_input_stream.tsx | 199 ++++++++++-------- 1 file changed, 107 insertions(+), 92 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/package_policy_input_stream.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/package_policy_input_stream.tsx index 3b591a0158d9c..7ca925e584939 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/package_policy_input_stream.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/package_policy_input_stream.tsx @@ -120,9 +120,6 @@ export const PackagePolicyInputStreamConfig = memo( } }, [isDefaultDatastream, containerRef]); - // Showing advanced options toggle state - const [isShowingAdvanced, setIsShowingAdvanced] = useState(isDefaultDatastream); - // Errors state const hasErrors = forceShowErrors && validationHasErrors(inputStreamValidationResults); @@ -171,6 +168,21 @@ export const PackagePolicyInputStreamConfig = memo( const datasetList = uniq(dataStreamsData?.data_streams) ?? []; const datastreams = sortDatastreamsByDataset(datasetList, packageInfo.name); + // Showing advanced options toggle state + const [isShowingAdvanced, setIsShowingAdvanced] = useState(isDefaultDatastream); + const hasAdvancedOptions = useMemo(() => { + return ( + advancedVars.length > 0 || + (isPackagePolicyEdit && showPipelinesAndMappings) || + isExperimentalDataStreamSettingsEnabled + ); + }, [ + advancedVars.length, + isExperimentalDataStreamSettingsEnabled, + isPackagePolicyEdit, + showPipelinesAndMappings, + ]); + return ( <> @@ -257,101 +269,104 @@ export const PackagePolicyInputStreamConfig = memo( ); })} - {/* Advanced section - always shown since we display experimental indexing settings here */} - - - - - setIsShowingAdvanced(!isShowingAdvanced)} - flush="left" - data-test-subj={`advancedStreamOptionsToggle-${packagePolicyInputStream.id}`} - > - - - - {!isShowingAdvanced && hasErrors && advancedVarsWithErrorsCount ? ( + + {/* Advanced section */} + {hasAdvancedOptions && ( + + + - + setIsShowingAdvanced(!isShowingAdvanced)} + flush="left" + data-test-subj={`advancedStreamOptionsToggle-${packagePolicyInputStream.id}`} + > - + - ) : null} - - - {isShowingAdvanced ? ( - <> - {advancedVars.map((varDef) => { - if (!packagePolicyInputStream.vars) return null; - const { name: varName, type: varType } = varDef; - const value = packagePolicyInputStream.vars?.[varName]?.value; + {!isShowingAdvanced && hasErrors && advancedVarsWithErrorsCount ? ( + + + + + + ) : null} + + + {isShowingAdvanced ? ( + <> + {advancedVars.map((varDef) => { + if (!packagePolicyInputStream.vars) return null; + const { name: varName, type: varType } = varDef; + const value = packagePolicyInputStream.vars?.[varName]?.value; - return ( - - { - updatePackagePolicyInputStream({ - vars: { - ...packagePolicyInputStream.vars, - [varName]: { - type: varType, - value: newValue, + return ( + + { + updatePackagePolicyInputStream({ + vars: { + ...packagePolicyInputStream.vars, + [varName]: { + type: varType, + value: newValue, + }, }, - }, - }); - }} - errors={inputStreamValidationResults?.vars![varName]} - forceShowErrors={forceShowErrors} - packageType={packageInfo.type} - packageName={packageInfo.name} - datastreams={datastreams} - isEditPage={isEditPage} - /> - - ); - })} - {isPackagePolicyEdit && showPipelinesAndMappings && ( - <> - - - - - - - - )} - {/* Experimental index/datastream settings e.g. synthetic source */} - {isExperimentalDataStreamSettingsEnabled && ( - - )} - - ) : null} - + }); + }} + errors={inputStreamValidationResults?.vars![varName]} + forceShowErrors={forceShowErrors} + packageType={packageInfo.type} + packageName={packageInfo.name} + datastreams={datastreams} + isEditPage={isEditPage} + /> + + ); + })} + {isPackagePolicyEdit && showPipelinesAndMappings && ( + <> + + + + + + + + )} + {/* Experimental index/datastream settings e.g. synthetic source */} + {isExperimentalDataStreamSettingsEnabled && ( + + )} + + ) : null} + + )} From a5de314687a195f4b73fb4b10bf6d3f7f5e58fd9 Mon Sep 17 00:00:00 2001 From: Cristina Amico Date: Tue, 11 Apr 2023 20:38:17 +0200 Subject: [PATCH 06/23] [Fleet] Logstash Output - prevent updating data_output_id for preconfigured policies (#154445) Closes https://github.com/elastic/kibana/issues/154326 ## Summary After the merge of https://github.com/elastic/kibana/pull/153226, when creating/updating a Logstash output as default, the `Elastic Cloud agent policy` preconfigured on Cloud gets reassigned to the "default" ES policy instead than keeping the `Elastic Cloud internal output`. Screenshot 2023-04-04 at 12 51 21 Tee bug is fixed by checking if any given fleet server policy is `preconfigured` or if it has already an assigned `data_output_id`, in which cases it doesn't get updated. ### Testing - Create an ES output additional to the default one - Create a preconfigured fleet server policy and make sure it has `fleet-server` integration (this is to simulate the preconfigured cloud policy) - Assign the previous output to the preconfigured policy - Now create a new `logstash` output and make it default - Check that the preconfigured policy maintains the custom output previously assigned ### 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> Co-authored-by: Nicolas Chaulet --- .../fleet/server/services/output.test.ts | 77 +++++++++++++-- .../plugins/fleet/server/services/output.ts | 94 ++++++++++++------- .../apis/outputs/crud.ts | 78 +++++++++++++-- 3 files changed, 196 insertions(+), 53 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/output.test.ts b/x-pack/plugins/fleet/server/services/output.test.ts index 11d6bf8936ee4..0f1ec2ffafa5b 100644 --- a/x-pack/plugins/fleet/server/services/output.test.ts +++ b/x-pack/plugins/fleet/server/services/output.test.ts @@ -189,6 +189,7 @@ describe('Output Service', () => { mockedAppContextService.getInternalUserSOClient.mockReset(); mockedAppContextService.getEncryptedSavedObjectsSetup.mockReset(); mockedAuditLoggingService.writeCustomSoAuditLog.mockReset(); + mockedAgentPolicyService.update.mockReset(); }); describe('create', () => { it('work with a predefined id', async () => { @@ -443,7 +444,7 @@ describe('Output Service', () => { expect.anything(), 'fleet_server_policy', { data_output_id: 'output-test' }, - { force: true } + { force: false } ); }); @@ -497,14 +498,6 @@ describe('Output Service', () => { }, { id: 'output-1' } ); - - expect(mockedAgentPolicyService.update).toBeCalledWith( - expect.anything(), - expect.anything(), - 'fleet_server_policy', - { data_output_id: 'output-test' }, - { force: true } - ); }); it('should call audit logger', async () => { @@ -798,6 +791,72 @@ describe('Output Service', () => { is_default: true, }); + expect(soClient.update).toBeCalledWith(expect.anything(), expect.anything(), { + type: 'logstash', + hosts: ['test:4343'], + is_default: true, + ca_sha256: null, + ca_trusted_fingerprint: null, + }); + expect(mockedAgentPolicyService.update).toBeCalledWith( + expect.anything(), + expect.anything(), + 'fleet_server_policy', + { data_output_id: 'output-test' }, + { force: false } + ); + }); + + it('Should update fleet server policies with data_output_id=default_output_id and force=true if a default ES output is changed to logstash, from preconfiguration', async () => { + const soClient = getMockedSoClient({ + defaultOutputId: 'output-test', + }); + mockedAgentPolicyService.list.mockResolvedValue({ + items: [ + { + name: 'fleet server policy', + id: 'fleet_server_policy', + is_default_fleet_server: true, + package_policies: [ + { + name: 'fleet-server-123', + package: { + name: 'fleet_server', + }, + }, + ], + }, + { + name: 'agent policy 1', + id: 'agent_policy_1', + is_managed: false, + package_policies: [ + { + name: 'nginx', + package: { + name: 'nginx', + }, + }, + ], + }, + ], + } as unknown as ReturnType); + mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); + + await outputService.update( + soClient, + esClientMock, + 'output-test', + { + type: 'logstash', + hosts: ['test:4343'], + is_default: true, + }, + { + fromPreconfiguration: true, + } + ); + expect(soClient.update).toBeCalledWith(expect.anything(), expect.anything(), { type: 'logstash', hosts: ['test:4343'], diff --git a/x-pack/plugins/fleet/server/services/output.ts b/x-pack/plugins/fleet/server/services/output.ts index eebf714716d19..214f73e72bdc9 100644 --- a/x-pack/plugins/fleet/server/services/output.ts +++ b/x-pack/plugins/fleet/server/services/output.ts @@ -165,7 +165,8 @@ async function validateTypeChanges( id: string, data: Partial, originalOutput: Output, - defaultDataOutputId: string | null + defaultDataOutputId: string | null, + fromPreconfiguration: boolean ) { const mergedIsDefault = data.is_default ?? originalOutput.is_default; const fleetServerPolicies = await findPoliciesWithFleetServer(soClient, id, mergedIsDefault); @@ -178,18 +179,42 @@ async function validateTypeChanges( // Validate no policy with fleet server use that policy validateLogstashOutputNotUsedInFleetServerPolicy(fleetServerPolicies); } - // if a logstash output is updated to become default, update the fleet server policies to use the previous ES output or default output - if (data?.type === outputType.Logstash && mergedIsDefault) { + await updateFleetServerPoliciesDataOutputId( + soClient, + esClient, + data, + mergedIsDefault, + defaultDataOutputId, + fleetServerPolicies, + fromPreconfiguration + ); +} + +async function updateFleetServerPoliciesDataOutputId( + soClient: SavedObjectsClientContract, + esClient: ElasticsearchClient, + data: Partial, + isDefault: boolean, + defaultDataOutputId: string | null, + fleetServerPolicies: AgentPolicy[], + fromPreconfiguration: boolean +) { + // if a logstash output is updated to become default + // if fleet server policies are don't have data_output_id or if they are using the new output + // update them to use the default output + if (data?.type === outputType.Logstash && isDefault) { for (const policy of fleetServerPolicies) { - await agentPolicyService.update( - soClient, - esClient, - policy.id, - { data_output_id: defaultDataOutputId }, - { - force: true, - } - ); + if (!policy.data_output_id || policy.data_output_id === data?.id) { + await agentPolicyService.update( + soClient, + esClient, + policy.id, + { + data_output_id: defaultDataOutputId, + }, + { force: fromPreconfiguration } + ); + } } } } @@ -302,6 +327,7 @@ class OutputService { options?: { id?: string; fromPreconfiguration?: boolean; overwrite?: boolean } ): Promise { const data: OutputSOAttributes = { ...omit(output, 'ssl') }; + const defaultDataOutputId = await this.getDefaultDataOutputId(soClient); if (output.type === outputType.Logstash) { await validateLogstashOutputNotUsedInAPMPolicy(soClient, undefined, data.is_default); @@ -311,34 +337,24 @@ class OutputService { ); } } - - if (data.type === outputType.Logstash) { - const defaultDataOutputId = await this.getDefaultDataOutputId(soClient); - const fleetServerPolicies = await findPoliciesWithFleetServer(soClient); - // if a logstash output is updated to become default, update the fleet server policies to use the previous ES output or default output - if (data.is_default) { - for (const policy of fleetServerPolicies) { - await agentPolicyService.update( - soClient, - esClient, - policy.id, - { data_output_id: defaultDataOutputId }, - { - force: true, - } - ); - } - } - } + const fleetServerPolicies = await findPoliciesWithFleetServer(soClient); + await updateFleetServerPoliciesDataOutputId( + soClient, + esClient, + data, + data.is_default, + defaultDataOutputId, + fleetServerPolicies, + options?.fromPreconfiguration ?? false + ); // ensure only default output exists if (data.is_default) { - const defaultDataOuputId = await this.getDefaultDataOutputId(soClient); - if (defaultDataOuputId) { + if (defaultDataOutputId) { await this.update( soClient, esClient, - defaultDataOuputId, + defaultDataOutputId, { is_default: false }, { fromPreconfiguration: options?.fromPreconfiguration ?? false } ); @@ -549,7 +565,15 @@ class OutputService { const mergedType = data.type ?? originalOutput.type; const defaultDataOutputId = await this.getDefaultDataOutputId(soClient); - await validateTypeChanges(soClient, esClient, id, data, originalOutput, defaultDataOutputId); + await validateTypeChanges( + soClient, + esClient, + id, + data, + originalOutput, + defaultDataOutputId, + fromPreconfiguration + ); // If the output type changed if (data.type && data.type !== originalOutput.type) { diff --git a/x-pack/test/fleet_api_integration/apis/outputs/crud.ts b/x-pack/test/fleet_api_integration/apis/outputs/crud.ts index 0c34c71d822f1..785a04b01c88c 100644 --- a/x-pack/test/fleet_api_integration/apis/outputs/crud.ts +++ b/x-pack/test/fleet_api_integration/apis/outputs/crud.ts @@ -27,6 +27,9 @@ export default function (providerContext: FtrProviderContext) { setupFleetAndAgents(providerContext); let defaultOutputId: string; + let ESOutputId: string; + let fleetServerPolicyId: string; + let fleetServerPolicyWithCustomOutputId: string; before(async function () { // we must first force install the fleet_server package to override package verification error on policy create @@ -53,6 +56,7 @@ export default function (providerContext: FtrProviderContext) { }) .expect(200); const fleetServerPolicy = apiResponse.item; + fleetServerPolicyId = fleetServerPolicy.id; ({ body: apiResponse } = await supertest .post(`/api/fleet/agent_policies`) @@ -92,6 +96,30 @@ export default function (providerContext: FtrProviderContext) { } defaultOutputId = defaultOutput.id; + + const { body: postResponse1 } = await supertest + .post(`/api/fleet/outputs`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'ESoutput', + type: 'elasticsearch', + hosts: ['https://test.fr'], + }) + .expect(200); + ESOutputId = postResponse1.item.id; + + ({ body: apiResponse } = await supertest + .post(`/api/fleet/agent_policies`) + .set('kbn-xsrf', 'kibana') + .send({ + name: 'Preconfigured Fleet Server policy', + namespace: 'default', + has_fleet_server: true, + data_output_id: `${ESOutputId}`, + }) + .expect(200)); + const fleetServerPolicyWithCustomOutput = apiResponse.item; + fleetServerPolicyWithCustomOutputId = fleetServerPolicyWithCustomOutput.id; }); after(async () => { @@ -100,10 +128,12 @@ export default function (providerContext: FtrProviderContext) { }); describe('GET /outputs', () => { - it('should list the default output', async () => { + it('should list all the outputs', async () => { const { body: getOutputsRes } = await supertest.get(`/api/fleet/outputs`).expect(200); - expect(getOutputsRes.items.length).to.eql(1); + expect(getOutputsRes.items.length).to.eql(2); + const findDefault = getOutputsRes.items.find((item: any) => item.is_default === true); + expect(findDefault.id).to.eql(defaultOutputId); }); }); @@ -160,7 +190,7 @@ export default function (providerContext: FtrProviderContext) { ); }); - it('should allow to update a default ES output keeping it ES', async function () { + it('should allow to update a default ES output if keeping it ES', async function () { await supertest .put(`/api/fleet/outputs/${defaultOutputId}`) .set('kbn-xsrf', 'xxxx') @@ -173,7 +203,7 @@ export default function (providerContext: FtrProviderContext) { }); it('should allow to update a non-default ES output to logstash', async function () { - const { body: postResponse } = await supertest + const { body: postResponse2 } = await supertest .post(`/api/fleet/outputs`) .set('kbn-xsrf', 'xxxx') .send({ @@ -188,7 +218,7 @@ export default function (providerContext: FtrProviderContext) { }) .expect(200); - const { id: logstashOutput1Id } = postResponse.item; + const { id: logstashOutput1Id } = postResponse2.item; await supertest .put(`/api/fleet/outputs/${logstashOutput1Id}`) .set('kbn-xsrf', 'xxxx') @@ -203,9 +233,19 @@ export default function (providerContext: FtrProviderContext) { }, }) .expect(200); + + const { body } = await supertest.get(`/api/fleet/agent_policies/${fleetServerPolicyId}`); + const updatedFleetServerPolicy = body.item; + expect(updatedFleetServerPolicy.data_output_id === defaultOutputId); + + const { body: bodyWithOutput } = await supertest.get( + `/api/fleet/agent_policies/${fleetServerPolicyWithCustomOutputId}` + ); + const updatedFleetServerPolicyWithCustomOutput = bodyWithOutput.item; + expect(updatedFleetServerPolicyWithCustomOutput.data_output_id === ESOutputId); }); - it('should allow to update a default logstash output to logstash', async function () { + it('should allow to update a default logstash output to logstash and fleet server policies should be updated', async function () { const { body: postResponse } = await supertest .post(`/api/fleet/outputs`) .set('kbn-xsrf', 'xxxx') @@ -238,6 +278,16 @@ export default function (providerContext: FtrProviderContext) { .expect(200); await supertest.get(`/api/fleet/outputs`).expect(200); + + const { body } = await supertest.get(`/api/fleet/agent_policies/${fleetServerPolicyId}`); + const updatedFleetServerPolicy = body.item; + expect(updatedFleetServerPolicy.data_output_id === defaultOutputId); + + const { body: bodyWithOutput } = await supertest.get( + `/api/fleet/agent_policies/${fleetServerPolicyWithCustomOutputId}` + ); + const updatedFleetServerPolicyWithCustomOutput = bodyWithOutput.item; + expect(updatedFleetServerPolicyWithCustomOutput.data_output_id === ESOutputId); }); it('should allow to update a logstash output with the shipper values', async function () { @@ -361,7 +411,7 @@ export default function (providerContext: FtrProviderContext) { }); }); - it('should allow to create a logstash output', async function () { + it('should allow to create a new logstash output', async function () { const { body: postResponse } = await supertest .post(`/api/fleet/outputs`) .set('kbn-xsrf', 'xxxx') @@ -392,7 +442,7 @@ export default function (providerContext: FtrProviderContext) { }); }); - it('should allow to create a new logstash default output', async function () { + it('should allow to create a new logstash default output and fleet server policies should not change', async function () { const { body: postResponse } = await supertest .post(`/api/fleet/outputs`) .set('kbn-xsrf', 'xxxx') @@ -422,6 +472,16 @@ export default function (providerContext: FtrProviderContext) { certificate_authorities: ['CA1', 'CA2'], }, }); + + const { body } = await supertest.get(`/api/fleet/agent_policies/${fleetServerPolicyId}`); + const updatedFleetServerPolicy = body.item; + expect(updatedFleetServerPolicy.data_output_id === defaultOutputId); + + const { body: bodyWithOutput } = await supertest.get( + `/api/fleet/agent_policies/${fleetServerPolicyWithCustomOutputId}` + ); + const updatedFleetServerPolicyWithCustomOutput = bodyWithOutput.item; + expect(updatedFleetServerPolicyWithCustomOutput.data_output_id === ESOutputId); }); it('should not allow to create a logstash output with http hosts ', async function () { @@ -445,7 +505,7 @@ export default function (providerContext: FtrProviderContext) { ); }); - it('should toggle default output when creating a new default output ', async function () { + it('should toggle the default output when creating a new one', async function () { await supertest .post(`/api/fleet/outputs`) .set('kbn-xsrf', 'xxxx') From e469ece932600a58ad5bea52e902eb6f4fde5b1b Mon Sep 17 00:00:00 2001 From: Kyle Pollich Date: Tue, 11 Apr 2023 15:02:36 -0400 Subject: [PATCH 07/23] [Fleet] Improve network error handling + add tests for Fleet agent versions build step (#154649) ## Summary Ref https://github.com/elastic/kibana/pull/154110 - Ensure we throw when the product versions API responds with an unsuccessful status code - Add tests for various success/failure cases around the agent versions list build step. cc @jen-huang --- .../tasks/fetch_agent_versions_list.test.ts | 116 ++++++++++++++++++ .../build/tasks/fetch_agent_versions_list.ts | 31 ++++- 2 files changed, 142 insertions(+), 5 deletions(-) create mode 100644 src/dev/build/tasks/fetch_agent_versions_list.test.ts diff --git a/src/dev/build/tasks/fetch_agent_versions_list.test.ts b/src/dev/build/tasks/fetch_agent_versions_list.test.ts new file mode 100644 index 0000000000000..707f6222de52e --- /dev/null +++ b/src/dev/build/tasks/fetch_agent_versions_list.test.ts @@ -0,0 +1,116 @@ +/* + * Copyright 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 fetch from 'node-fetch'; + +import { REPO_ROOT } from '@kbn/repo-info'; +import { ToolingLog } from '@kbn/tooling-log'; + +import { FetchAgentVersionsList } from './fetch_agent_versions_list'; +import { Build, Config, write } from '../lib'; + +jest.mock('node-fetch'); +jest.mock('../lib'); + +const config = new Config( + true, + { + version: '8.0.0', + engines: { + node: '*', + }, + workspaces: { + packages: [], + }, + } as any, + '1.2.3', + REPO_ROOT, + { + buildNumber: 1234, + buildSha: 'abcd1234', + buildVersion: '8.0.0', + }, + false, + false, + null, + '', + '', + false, + true, + true, + {} +); + +const mockedFetch = fetch as jest.MockedFunction; +const mockedWrite = write as jest.MockedFunction; +const mockedBuild = new Build(config); + +describe('FetchAgentVersionsList', () => { + beforeEach(() => { + mockedFetch.mockReset(); + (mockedBuild.resolvePath as jest.Mock).mockReset(); + mockedWrite.mockReset(); + }); + + describe('when valid JSON is returned from versions endpoint', () => { + it('does not throw', async () => { + mockedFetch.mockResolvedValueOnce({ + status: 200, + text: jest.fn().mockResolvedValueOnce( + JSON.stringify([ + [ + { + title: 'Elastic Agent 8.0.0', + version_number: '8.0.0', + }, + { + title: 'Elastic Agent 8.0.1', + version_number: '8.0.1', + }, + ], + ]) + ), + } as any); + + await FetchAgentVersionsList.run(config, new ToolingLog(), mockedBuild); + + expect(mockedWrite).toHaveBeenCalledTimes(1); + }); + }); + + describe('when a network error is thrown', () => { + it('throws', async () => { + mockedFetch.mockResolvedValueOnce({ + status: 503, + text: jest.fn().mockResolvedValueOnce('Gateway timeout'), + } as any); + + try { + await FetchAgentVersionsList.run(config, new ToolingLog(), mockedBuild); + } catch (error) { + expect(error).toBeTruthy(); + expect(mockedWrite).not.toHaveBeenCalled(); + } + }); + }); + + describe('when invalid json is returned from versions endpoint', () => { + it('throws', async () => { + mockedFetch.mockResolvedValueOnce({ + status: 200, + text: jest.fn().mockResolvedValueOnce('not json'), + } as any); + + try { + await FetchAgentVersionsList.run(config, new ToolingLog(), mockedBuild); + } catch (error) { + expect(error).toBeTruthy(); + expect(mockedWrite).not.toHaveBeenCalled(); + } + }); + }); +}); diff --git a/src/dev/build/tasks/fetch_agent_versions_list.ts b/src/dev/build/tasks/fetch_agent_versions_list.ts index 560c52fad07ba..3ff42e2ae11b0 100644 --- a/src/dev/build/tasks/fetch_agent_versions_list.ts +++ b/src/dev/build/tasks/fetch_agent_versions_list.ts @@ -19,12 +19,18 @@ const getAvailableVersions = async (log: ToolingLog) => { }; // Endpoint maintained by the web-team and hosted on the elastic website // See https://github.com/elastic/website-development/issues/9331 - const url = 'https://www.elastic.co/api/product_versions'; + const url = 'https://www.elastic.co/content/product_versions'; + log.info('Fetching Elastic Agent versions list'); + try { - log.info('Fetching Elastic Agent versions list'); const results = await fetch(url, options); + const rawBody = await results.text(); + + if (results.status >= 400) { + throw new Error(`Status code ${results.status} received from versions API: ${rawBody}`); + } - const jsonBody = await results.json(); + const jsonBody = JSON.parse(rawBody); const versions: string[] = (jsonBody.length ? jsonBody[0] : []) .filter((item: any) => item?.title?.includes('Elastic Agent')) @@ -33,8 +39,18 @@ const getAvailableVersions = async (log: ToolingLog) => { log.info(`Retrieved available versions`); return versions; } catch (error) { - log.warning(`Failed to fetch versions list`); - log.warning(error); + const errorMessage = 'Failed to fetch Elastic Agent versions list'; + + if (process.env.BUILDKITE_PULL_REQUEST === 'true') { + // For PR jobs, just log the error as a warning and continue + log.warning(errorMessage); + log.warning(error); + } else { + // For non-PR jobs like nightly builds, log the error to stderror and throw + // to ensure the build fails + log.error(errorMessage); + throw new Error(error); + } } return []; }; @@ -44,6 +60,11 @@ export const FetchAgentVersionsList: Task = { description: 'Build list of available Elastic Agent versions for Fleet UI', async run(config, log, build) { + // Agent version list task is skipped for PR's, so as not to overwhelm the versions API + if (process.env.BUILDKITE_PULL_REQUEST === 'true') { + return; + } + const versionsList = await getAvailableVersions(log); const AGENT_VERSION_BUILD_FILE = 'x-pack/plugins/fleet/target/agent_versions_list.json'; From 56796db2c067ea5f6bb7b0bdc0882c217aefb57c Mon Sep 17 00:00:00 2001 From: Zacqary Adam Xeper Date: Tue, 11 Apr 2023 14:13:54 -0500 Subject: [PATCH 08/23] [RAM] [FE] Add conditional actions UI for timeframe (#153944) ## Summary Adds the conditional timeframe to the actions UI. **Currently only enabled in the Security Solution alerts UI using the `showActionAlertsFilter` prop** Part of https://github.com/elastic/kibana/issues/152026 and https://github.com/elastic/kibana/issues/152611 Screenshot 2023-03-29 at 4 15 24 PM ### UPDATED UI Screenshot 2023-03-31 at 3 58 12 PM ### 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)) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../src/actions/index.ts | 37 ++- x-pack/plugins/alerting/common/rule.ts | 5 +- .../alerting/server/routes/get_rule.ts | 23 +- .../public/alerts/alert_form.test.tsx | 11 +- .../detection_engine/transform_actions.ts | 4 + .../common/detection_engine/types.ts | 3 +- .../rules/rule_actions_field/index.tsx | 26 ++- .../lib/rule_api/common_transformations.ts | 2 + .../public/application/lib/rule_api/create.ts | 3 +- .../public/application/lib/rule_api/update.ts | 3 +- .../action_alerts_filter_timeframe.test.tsx | 135 +++++++++++ .../action_alerts_filter_timeframe.tsx | 221 ++++++++++++++++++ .../action_form.test.tsx | 9 + .../action_connector_form/action_form.tsx | 16 +- .../action_type_form.test.tsx | 7 + .../action_type_form.tsx | 25 +- .../sections/rule_form/rule_form.tsx | 9 + .../sections/rule_form/rule_reducer.ts | 41 +++- .../recurrence_scheduler/constants.ts | 8 +- .../public/common/constants/i18n_weekdays.ts | 20 ++ .../public/common/constants/index.ts | 1 + 21 files changed, 574 insertions(+), 35 deletions(-) create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_timeframe.test.tsx create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_timeframe.tsx create mode 100644 x-pack/plugins/triggers_actions_ui/public/common/constants/i18n_weekdays.ts diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts index baa36d97682ba..b173d67c9f005 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts +++ b/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts @@ -29,6 +29,39 @@ export const RuleActionUuid = NonEmptyString; export type RuleActionParams = t.TypeOf; export const RuleActionParams = saved_object_attributes; +export const RuleActionAlertsFilter = t.strict({ + query: t.union([ + t.null, + t.intersection([ + t.strict({ + kql: t.string, + }), + t.partial({ dsl: t.string }), + ]), + ]), + timeframe: t.union([ + t.null, + t.strict({ + timezone: t.string, + days: t.array( + t.union([ + t.literal(1), + t.literal(2), + t.literal(3), + t.literal(4), + t.literal(5), + t.literal(6), + t.literal(7), + ]) + ), + hours: t.strict({ + start: t.string, + end: t.string, + }), + }), + ]), +}); + export type RuleAction = t.TypeOf; export const RuleAction = t.exact( t.intersection([ @@ -38,7 +71,7 @@ export const RuleAction = t.exact( action_type_id: RuleActionTypeId, params: RuleActionParams, }), - t.partial({ uuid: RuleActionUuid }), + t.partial({ uuid: RuleActionUuid, alerts_filter: RuleActionAlertsFilter }), ]) ); @@ -54,7 +87,7 @@ export const RuleActionCamel = t.exact( actionTypeId: RuleActionTypeId, params: RuleActionParams, }), - t.partial({ uuid: RuleActionUuid }), + t.partial({ uuid: RuleActionUuid, alertsFilter: RuleActionAlertsFilter }), ]) ); diff --git a/x-pack/plugins/alerting/common/rule.ts b/x-pack/plugins/alerting/common/rule.ts index e2b42e8ccf292..980dccf632f6b 100644 --- a/x-pack/plugins/alerting/common/rule.ts +++ b/x-pack/plugins/alerting/common/rule.ts @@ -77,8 +77,9 @@ export interface RuleExecutionStatus { export type RuleActionParams = SavedObjectAttributes; export type RuleActionParam = SavedObjectAttribute; +export type IsoWeekday = 1 | 2 | 3 | 4 | 5 | 6 | 7; export interface AlertsFilterTimeframe extends SavedObjectAttributes { - days: Array<1 | 2 | 3 | 4 | 5 | 6 | 7>; + days: IsoWeekday[]; timezone: string; hours: { start: string; @@ -94,6 +95,8 @@ export interface AlertsFilter extends SavedObjectAttributes { timeframe: null | AlertsFilterTimeframe; } +export type RuleActionAlertsFilterProperty = AlertsFilterTimeframe | RuleActionParam; + export interface RuleAction { uuid?: string; group: string; diff --git a/x-pack/plugins/alerting/server/routes/get_rule.ts b/x-pack/plugins/alerting/server/routes/get_rule.ts index ab84f0c16a5e2..bc7983f6acdf1 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule.ts @@ -9,7 +9,12 @@ import { omit } from 'lodash'; import { schema } from '@kbn/config-schema'; import { IRouter } from '@kbn/core/server'; import { ILicenseState } from '../lib'; -import { verifyAccessAndContext, RewriteResponseCase, rewriteRuleLastRun } from './lib'; +import { + verifyAccessAndContext, + RewriteResponseCase, + rewriteRuleLastRun, + rewriteActionsRes, +} from './lib'; import { RuleTypeParams, AlertingRequestHandlerContext, @@ -61,21 +66,7 @@ const rewriteBodyRes: RewriteResponseCase> = ({ last_execution_date: executionStatus.lastExecutionDate, last_duration: executionStatus.lastDuration, }, - actions: actions.map(({ group, id, actionTypeId, params, frequency, uuid, alertsFilter }) => ({ - group, - id, - params, - connector_type_id: actionTypeId, - frequency: frequency - ? { - summary: frequency.summary, - notify_when: frequency.notifyWhen, - throttle: frequency.throttle, - } - : undefined, - ...(uuid && { uuid }), - ...(alertsFilter && { alerts_filter: alertsFilter }), - })), + actions: rewriteActionsRes(actions), ...(lastRun ? { last_run: rewriteRuleLastRun(lastRun) } : {}), ...(nextRun ? { next_run: nextRun } : {}), ...(viewInAppRelativeUrl ? { view_in_app_relative_url: viewInAppRelativeUrl } : {}), diff --git a/x-pack/plugins/monitoring/public/alerts/alert_form.test.tsx b/x-pack/plugins/monitoring/public/alerts/alert_form.test.tsx index ecf11fa122b36..82baf344dfff7 100644 --- a/x-pack/plugins/monitoring/public/alerts/alert_form.test.tsx +++ b/x-pack/plugins/monitoring/public/alerts/alert_form.test.tsx @@ -47,6 +47,10 @@ jest.mock('@kbn/triggers-actions-ui-plugin/public/application/lib/rule_api', () loadAlertTypes: jest.fn(), })); +jest.mock('@kbn/kibana-react-plugin/public/ui_settings/use_ui_setting', () => ({ + useUiSetting: jest.fn().mockImplementation((_, defaultValue) => defaultValue), +})); + const initLegacyShims = () => { const triggersActionsUi = { actionTypeRegistry: actionTypeRegistryMock.create(), @@ -237,10 +241,13 @@ describe('alert_form', () => { initialAlert.actions[index].id = id; }} setActions={(_updatedActions: AlertAction[]) => {}} - setActionParamsProperty={(key: string, value: any, index: number) => + setActionParamsProperty={(key: string, value: unknown, index: number) => + (initialAlert.actions[index] = { ...initialAlert.actions[index], [key]: value }) + } + setActionFrequencyProperty={(key: string, value: unknown, index: number) => (initialAlert.actions[index] = { ...initialAlert.actions[index], [key]: value }) } - setActionFrequencyProperty={(key: string, value: any, index: number) => + setActionAlertsFilterProperty={(key: string, value: unknown, index: number) => (initialAlert.actions[index] = { ...initialAlert.actions[index], [key]: value }) } actionTypeRegistry={actionTypeRegistry} diff --git a/x-pack/plugins/security_solution/common/detection_engine/transform_actions.ts b/x-pack/plugins/security_solution/common/detection_engine/transform_actions.ts index 8561226f98744..1b74bcd320aad 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/transform_actions.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/transform_actions.ts @@ -16,11 +16,13 @@ export const transformRuleToAlertAction = ({ action_type_id: actionTypeId, params, uuid, + alerts_filter: alertsFilter, }: RuleAlertAction): RuleAction => ({ group, id, params, actionTypeId, + ...(alertsFilter && { alertsFilter }), ...(uuid && { uuid }), }); @@ -30,11 +32,13 @@ export const transformAlertToRuleAction = ({ actionTypeId, params, uuid, + alertsFilter, }: RuleAction): RuleAlertAction => ({ group, id, params, action_type_id: actionTypeId, + ...(alertsFilter && { alerts_filter: alertsFilter }), ...(uuid && { uuid }), }); diff --git a/x-pack/plugins/security_solution/common/detection_engine/types.ts b/x-pack/plugins/security_solution/common/detection_engine/types.ts index dad66ce3f8641..1b3976e91b3c5 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/types.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/types.ts @@ -7,8 +7,9 @@ import type { RuleAction } from '@kbn/alerting-plugin/common'; -export type RuleAlertAction = Omit & { +export type RuleAlertAction = Omit & { action_type_id: string; + alerts_filter?: RuleAction['alertsFilter']; }; /** diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_field/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_field/index.tsx index 351ec349d376c..591e3518af8d7 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_field/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_field/index.tsx @@ -13,7 +13,11 @@ import ReactMarkdown from 'react-markdown'; import styled from 'styled-components'; import type { ActionVariables } from '@kbn/triggers-actions-ui-plugin/public'; -import type { RuleAction, RuleActionParam } from '@kbn/alerting-plugin/common'; +import type { + RuleAction, + RuleActionAlertsFilterProperty, + RuleActionParam, +} from '@kbn/alerting-plugin/common'; import { SecurityConnectorFeatureId } from '@kbn/actions-plugin/common'; import type { FieldHook } from '../../../../shared_imports'; import { useFormContext } from '../../../../shared_imports'; @@ -131,6 +135,23 @@ export const RuleActionsField: React.FC = ({ field, messageVariables }) = [field, isInitializingAction] ); + const setActionAlertsFilterProperty = useCallback( + (key: string, value: RuleActionAlertsFilterProperty, index: number) => { + field.setValue((prevValue: RuleAction[]) => { + const updatedActions = [...prevValue]; + updatedActions[index] = { + ...updatedActions[index], + alertsFilter: { + ...(updatedActions[index].alertsFilter ?? { query: null, timeframe: null }), + [key]: value, + }, + }; + return updatedActions; + }); + }, + [field] + ); + const actionForm = useMemo( () => getActionForm({ @@ -141,10 +162,12 @@ export const RuleActionsField: React.FC = ({ field, messageVariables }) = setActions: setAlertActionsProperty, setActionParamsProperty, setActionFrequencyProperty: () => {}, + setActionAlertsFilterProperty, featureId: SecurityConnectorFeatureId, defaultActionMessage: DEFAULT_ACTION_MESSAGE, hideActionHeader: true, hideNotifyWhen: true, + showActionAlertsFilter: true, }), [ actions, @@ -153,6 +176,7 @@ export const RuleActionsField: React.FC = ({ field, messageVariables }) = setActionIdByIndex, setActionParamsProperty, setAlertActionsProperty, + setActionAlertsFilterProperty, ] ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/common_transformations.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/common_transformations.ts index 97b17f460f3d4..11a2ae2588c29 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/common_transformations.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/common_transformations.ts @@ -15,6 +15,7 @@ const transformAction: RewriteRequestCase = ({ connector_type_id: actionTypeId, params, frequency, + alerts_filter: alertsFilter, }) => ({ group, id, @@ -29,6 +30,7 @@ const transformAction: RewriteRequestCase = ({ }, } : {}), + ...(alertsFilter ? { alertsFilter } : {}), ...(uuid && { uuid }), }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/create.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/create.ts index 9d13b5f909c23..ed56bcdb3ca7d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/create.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/create.ts @@ -27,7 +27,7 @@ const rewriteBodyRequest: RewriteResponseCase = ({ }): any => ({ ...res, rule_type_id: ruleTypeId, - actions: actions.map(({ group, id, params, frequency }) => ({ + actions: actions.map(({ group, id, params, frequency, alertsFilter }) => ({ group, id, params, @@ -36,6 +36,7 @@ const rewriteBodyRequest: RewriteResponseCase = ({ throttle: frequency!.throttle, summary: frequency!.summary, }, + alertsFilter, })), }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/update.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/update.ts index 51c6febf6c557..15097eb03f156 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/update.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/update.ts @@ -17,7 +17,7 @@ type RuleUpdatesBody = Pick< >; const rewriteBodyRequest: RewriteResponseCase = ({ actions, ...res }): any => ({ ...res, - actions: actions.map(({ group, id, params, frequency, uuid }) => ({ + actions: actions.map(({ group, id, params, frequency, uuid, alertsFilter }) => ({ group, id, params, @@ -26,6 +26,7 @@ const rewriteBodyRequest: RewriteResponseCase = ({ actions, ... throttle: frequency!.throttle, summary: frequency!.summary, }, + alertsFilter, ...(uuid && { uuid }), })), }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_timeframe.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_timeframe.test.tsx new file mode 100644 index 0000000000000..a4c3edfda3344 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_timeframe.test.tsx @@ -0,0 +1,135 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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 { mountWithIntl, nextTick } from '@kbn/test-jest-helpers'; +import { act } from 'react-dom/test-utils'; +import { ActionAlertsFilterTimeframe } from './action_alerts_filter_timeframe'; +import { AlertsFilterTimeframe } from '@kbn/alerting-plugin/common'; +import { Moment } from 'moment'; + +jest.mock('@kbn/kibana-react-plugin/public/ui_settings/use_ui_setting', () => ({ + useUiSetting: jest.fn().mockImplementation((_, defaultValue) => defaultValue), +})); + +describe('action_alerts_filter_timeframe', () => { + async function setup(timeframe: AlertsFilterTimeframe | null) { + const wrapper = mountWithIntl( + {}} /> + ); + + // Wait for active space to resolve before requesting the component to update + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + return wrapper; + } + + it('renders an unchecked switch when passed a null timeframe', async () => { + const wrapper = await setup(null); + + const alertsFilterTimeframeToggle = wrapper.find( + '[data-test-subj="alertsFilterTimeframeToggle"]' + ); + + expect(alertsFilterTimeframeToggle.first().props().checked).toBeFalsy(); + }); + + it('renders the passed in timeframe', async () => { + const wrapper = await setup({ + days: [6, 7], + timezone: 'America/Chicago', + hours: { start: '10:00', end: '20:00' }, + }); + + const alertsFilterTimeframeToggle = wrapper.find( + '[data-test-subj="alertsFilterTimeframeToggle"]' + ); + + expect(alertsFilterTimeframeToggle.first().props().checked).toBeTruthy(); + + const alertsFilterTimeframeWeekdayButtons = wrapper.find( + '[data-test-subj="alertsFilterTimeframeWeekdayButtons"]' + ); + expect(alertsFilterTimeframeWeekdayButtons.exists()).toBeTruthy(); + // Use Reflect.get to avoid typescript errors + expect( + Reflect.get( + alertsFilterTimeframeWeekdayButtons.find('[data-test-subj="1"]').first().props(), + 'isSelected' + ) + ).toBeFalsy(); + expect( + Reflect.get( + alertsFilterTimeframeWeekdayButtons.find('[data-test-subj="2"]').first().props(), + 'isSelected' + ) + ).toBeFalsy(); + expect( + Reflect.get( + alertsFilterTimeframeWeekdayButtons.find('[data-test-subj="3"]').first().props(), + 'isSelected' + ) + ).toBeFalsy(); + expect( + Reflect.get( + alertsFilterTimeframeWeekdayButtons.find('[data-test-subj="4"]').first().props(), + 'isSelected' + ) + ).toBeFalsy(); + expect( + Reflect.get( + alertsFilterTimeframeWeekdayButtons.find('[data-test-subj="5"]').first().props(), + 'isSelected' + ) + ).toBeFalsy(); + expect( + Reflect.get( + alertsFilterTimeframeWeekdayButtons.find('[data-test-subj="6"]').first().props(), + 'isSelected' + ) + ).toBeTruthy(); + expect( + Reflect.get( + alertsFilterTimeframeWeekdayButtons.find('[data-test-subj="6"]').first().props(), + 'isSelected' + ) + ).toBeTruthy(); + + const alertsFilterTimeframeStart = wrapper.find( + '[data-test-subj="alertsFilterTimeframeStart"]' + ); + expect(alertsFilterTimeframeStart.exists()).toBeTruthy(); + { + const selectedDate: Moment = Reflect.get( + alertsFilterTimeframeStart.first().props(), + 'selected' + ); + expect(selectedDate.format('HH:mm')).toEqual('10:00'); + } + + const alertsFilterTimeframeEnd = wrapper.find('[data-test-subj="alertsFilterTimeframeEnd"]'); + expect(alertsFilterTimeframeEnd.exists()).toBeTruthy(); + { + const selectedDate: Moment = Reflect.get( + alertsFilterTimeframeEnd.first().props(), + 'selected' + ); + expect(selectedDate.format('HH:mm')).toEqual('20:00'); + } + + const alertsFilterTimeframeTimezone = wrapper.find( + '[data-test-subj="alertsFilterTimeframeTimezone"]' + ); + expect(alertsFilterTimeframeTimezone.exists()).toBeTruthy(); + expect( + Reflect.get(alertsFilterTimeframeTimezone.first().props(), 'selectedOptions')[0].label + ).toEqual('America/Chicago'); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_timeframe.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_timeframe.tsx new file mode 100644 index 0000000000000..a8e276f81535f --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_timeframe.tsx @@ -0,0 +1,221 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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, { Moment } from 'moment'; +import React, { useState, useCallback, useMemo, useEffect } from 'react'; +import { useUiSetting } from '@kbn/kibana-react-plugin/public'; +import { i18n } from '@kbn/i18n'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiSwitch, + EuiButtonGroup, + EuiSpacer, + EuiDatePickerRange, + EuiDatePicker, + EuiComboBox, +} from '@elastic/eui'; +import deepEqual from 'fast-deep-equal'; +import { AlertsFilterTimeframe, IsoWeekday } from '@kbn/alerting-plugin/common'; +import { I18N_WEEKDAY_OPTIONS_DDD, ISO_WEEKDAYS } from '../../../common/constants'; + +interface ActionAlertsFilterTimeframeProps { + state: AlertsFilterTimeframe | null; + onChange: (update: AlertsFilterTimeframe | null) => void; +} + +const TIMEZONE_OPTIONS = moment.tz?.names().map((n) => ({ label: n })) ?? [{ label: 'UTC' }]; + +const useSortedWeekdayOptions = () => { + const kibanaDow: string = useUiSetting('dateFormat:dow'); + const startDow = kibanaDow ?? 'Sunday'; + const startDowIndex = I18N_WEEKDAY_OPTIONS_DDD.findIndex((o) => o.label.startsWith(startDow)); + return [ + ...I18N_WEEKDAY_OPTIONS_DDD.slice(startDowIndex), + ...I18N_WEEKDAY_OPTIONS_DDD.slice(0, startDowIndex), + ]; +}; + +const useDefaultTimezone = () => { + const kibanaTz: string = useUiSetting('dateFormat:tz'); + if (!kibanaTz || kibanaTz === 'Browser') return moment.tz?.guess() ?? 'UTC'; + return kibanaTz; +}; + +const useTimeframe = (initialTimeframe: AlertsFilterTimeframe | null) => { + const timezone = useDefaultTimezone(); + const DEFAULT_TIMEFRAME = { + days: [], + timezone, + hours: { + start: '00:00', + end: '24:00', + }, + }; + return useState(initialTimeframe || DEFAULT_TIMEFRAME); +}; +const useTimeFormat = () => { + const dateFormatScaled: Array<[string, string]> = useUiSetting('dateFormat:scaled') ?? [ + ['PT1M', 'HH:mm'], + ]; + const [, PT1M] = dateFormatScaled.find(([key]) => key === 'PT1M') ?? ['', 'HH:mm']; + return PT1M; +}; + +export const ActionAlertsFilterTimeframe: React.FC = ({ + state, + onChange, +}) => { + const timeFormat = useTimeFormat(); + const [timeframe, setTimeframe] = useTimeframe(state); + const [selectedTimezone, setSelectedTimezone] = useState([{ label: timeframe.timezone }]); + + const timeframeEnabled = useMemo(() => Boolean(state), [state]); + + const weekdayOptions = useSortedWeekdayOptions(); + + useEffect(() => { + const nextState = timeframeEnabled ? timeframe : null; + if (!deepEqual(state, nextState)) onChange(nextState); + }, [timeframeEnabled, timeframe, state, onChange]); + + const toggleTimeframe = useCallback( + () => onChange(state ? null : timeframe), + [state, timeframe, onChange] + ); + const updateTimeframe = useCallback( + (update: Partial) => { + setTimeframe({ + ...timeframe, + ...update, + }); + }, + [timeframe, setTimeframe] + ); + + const onChangeHours = useCallback( + (startOrEnd: 'start' | 'end') => (date: Moment) => { + updateTimeframe({ + hours: { ...timeframe.hours, [startOrEnd]: date.format('HH:mm') }, + }); + }, + [updateTimeframe, timeframe] + ); + + const onToggleWeekday = useCallback( + (id: string) => { + if (!timeframe) return; + const day = Number(id) as IsoWeekday; + const previouslyHasDay = timeframe.days.includes(day); + const newDays = previouslyHasDay + ? timeframe.days.filter((d) => d !== day) + : [...timeframe.days, day]; + updateTimeframe({ days: newDays }); + }, + [timeframe, updateTimeframe] + ); + const selectedWeekdays = useMemo( + () => + ISO_WEEKDAYS.reduce( + (result, day) => ({ ...result, [day]: timeframe.days.includes(day) }), + {} + ), + [timeframe] + ); + + const onChangeTimezone = useCallback( + (value) => { + setSelectedTimezone(value); + if (value[0].label) updateTimeframe({ timezone: value[0].label }); + }, + [updateTimeframe, setSelectedTimezone] + ); + + const [startH, startM] = useMemo(() => timeframe.hours.start.split(':').map(Number), [timeframe]); + const [endH, endM] = useMemo(() => timeframe.hours.end.split(':').map(Number), [timeframe]); + + return ( + <> + + {timeframeEnabled && ( + <> + + + + + + + + + } + endDateControl={ + + } + /> + + + + + + + )} + + ); +}; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.test.tsx index 5c4aaa79f0d95..18a8a577b7e0f 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.test.tsx @@ -347,6 +347,15 @@ describe('action_form', () => { frequency: { ...initialAlert.actions[index].frequency!, [key]: value }, }) } + setActionAlertsFilterProperty={(key: string, value: any, index: number) => + (initialAlert.actions[index] = { + ...initialAlert.actions[index], + alertsFilter: { + ...(initialAlert.actions[index].alertsFilter ?? { query: null, timeframe: null }), + [key]: value, + }, + }) + } actionTypeRegistry={actionTypeRegistry} setHasActionsWithBrokenConnector={setHasActionsWithBrokenConnector} /> diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx index cc2810897bb08..0a8d2d7cd88f9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx @@ -19,7 +19,11 @@ import { EuiToolTip, EuiLink, } from '@elastic/eui'; -import { ActionGroup, RuleActionParam } from '@kbn/alerting-plugin/common'; +import { + ActionGroup, + RuleActionAlertsFilterProperty, + RuleActionParam, +} from '@kbn/alerting-plugin/common'; import { betaBadgeProps } from './beta_badge_props'; import { loadActionTypes, loadAllActions as loadConnectors } from '../../lib/action_connector_api'; import { @@ -56,6 +60,11 @@ export interface ActionAccordionFormProps { setActions: (actions: RuleAction[]) => void; setActionParamsProperty: (key: string, value: RuleActionParam, index: number) => void; setActionFrequencyProperty: (key: string, value: RuleActionParam, index: number) => void; + setActionAlertsFilterProperty: ( + key: string, + value: RuleActionAlertsFilterProperty, + index: number + ) => void; featureId: string; messageVariables?: ActionVariables; setHasActionsDisabled?: (value: boolean) => void; @@ -68,6 +77,7 @@ export interface ActionAccordionFormProps { defaultSummaryMessage?: string; hasSummary?: boolean; minimumThrottleInterval?: [number | undefined, string]; + showActionAlertsFilter?: boolean; } interface ActiveActionConnectorState { @@ -83,6 +93,7 @@ export const ActionForm = ({ setActions, setActionParamsProperty, setActionFrequencyProperty, + setActionAlertsFilterProperty, featureId, messageVariables, actionGroups, @@ -97,6 +108,7 @@ export const ActionForm = ({ defaultSummaryMessage, hasSummary, minimumThrottleInterval, + showActionAlertsFilter, }: ActionAccordionFormProps) => { const { http, @@ -373,6 +385,7 @@ export const ActionForm = ({ key={`action-form-action-at-${index}`} setActionParamsProperty={setActionParamsProperty} setActionFrequencyProperty={setActionFrequencyProperty} + setActionAlertsFilterProperty={setActionAlertsFilterProperty} actionTypesIndex={actionTypesIndex} connectors={connectors} defaultActionGroupId={defaultActionGroupId} @@ -402,6 +415,7 @@ export const ActionForm = ({ defaultSummaryMessage={defaultSummaryMessage} hasSummary={hasSummary} minimumThrottleInterval={minimumThrottleInterval} + showActionAlertsFilter={showActionAlertsFilter} /> ); })} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx index d2a443ee208a3..ffc7e3fd612be 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx @@ -36,6 +36,10 @@ jest.mock('../../lib/action_variables', () => { }; }); +jest.mock('@kbn/kibana-react-plugin/public/ui_settings/use_ui_setting', () => ({ + useUiSetting: jest.fn().mockImplementation((_, defaultValue) => defaultValue), +})); + describe('action_type_form', () => { afterEach(() => { jest.clearAllMocks(); @@ -376,6 +380,7 @@ function getActionTypeForm({ onDeleteAction, onConnectorSelected, setActionFrequencyProperty, + setActionAlertsFilterProperty, hasSummary = true, messageVariables = { context: [], state: [], params: [] }, }: { @@ -389,6 +394,7 @@ function getActionTypeForm({ onDeleteAction?: () => void; onConnectorSelected?: (id: string) => void; setActionFrequencyProperty?: () => void; + setActionAlertsFilterProperty?: () => void; hasSummary?: boolean; messageVariables?: ActionVariables; }) { @@ -469,6 +475,7 @@ function getActionTypeForm({ defaultActionGroupId={defaultActionGroupId ?? 'default'} setActionParamsProperty={jest.fn()} setActionFrequencyProperty={setActionFrequencyProperty ?? jest.fn()} + setActionAlertsFilterProperty={setActionAlertsFilterProperty ?? jest.fn()} index={index ?? 1} actionTypesIndex={actionTypeIndex ?? actionTypeIndexDefault} actionTypeRegistry={actionTypeRegistry} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx index b5df2e5d6ac6b..c7a2f10ebc466 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx @@ -30,7 +30,11 @@ import { EuiCallOut, } from '@elastic/eui'; import { isEmpty, partition, some } from 'lodash'; -import { ActionVariable, RuleActionParam } from '@kbn/alerting-plugin/common'; +import { + ActionVariable, + RuleActionAlertsFilterProperty, + RuleActionParam, +} from '@kbn/alerting-plugin/common'; import { getDurationNumberInItsUnit, getDurationUnitValue, @@ -54,6 +58,7 @@ import { useKibana } from '../../../common/lib/kibana'; import { ConnectorsSelection } from './connectors_selection'; import { ActionNotifyWhen } from './action_notify_when'; import { validateParamsForWarnings } from '../../lib/validate_params_for_warnings'; +import { ActionAlertsFilterTimeframe } from './action_alerts_filter_timeframe'; export type ActionTypeFormProps = { actionItem: RuleAction; @@ -64,6 +69,11 @@ export type ActionTypeFormProps = { onDeleteAction: () => void; setActionParamsProperty: (key: string, value: RuleActionParam, index: number) => void; setActionFrequencyProperty: (key: string, value: RuleActionParam, index: number) => void; + setActionAlertsFilterProperty: ( + key: string, + value: RuleActionAlertsFilterProperty, + index: number + ) => void; actionTypesIndex: ActionTypeIndex; connectors: ActionConnector[]; actionTypeRegistry: ActionTypeRegistryContract; @@ -72,6 +82,7 @@ export type ActionTypeFormProps = { hideNotifyWhen?: boolean; hasSummary?: boolean; minimumThrottleInterval?: [number | undefined, string]; + showActionAlertsFilter?: boolean; } & Pick< ActionAccordionFormProps, | 'defaultActionGroupId' @@ -99,6 +110,7 @@ export const ActionTypeForm = ({ onDeleteAction, setActionParamsProperty, setActionFrequencyProperty, + setActionAlertsFilterProperty, actionTypesIndex, connectors, defaultActionGroupId, @@ -113,6 +125,7 @@ export const ActionTypeForm = ({ defaultSummaryMessage, hasSummary, minimumThrottleInterval, + showActionAlertsFilter, }: ActionTypeFormProps) => { const { application: { capabilities }, @@ -143,6 +156,7 @@ export const ActionTypeForm = ({ const [warning, setWarning] = useState(null); const [useDefaultMessage, setUseDefaultMessage] = useState(false); + const isSummaryAction = actionItem.frequency?.summary; const getDefaultParams = async () => { @@ -380,6 +394,15 @@ export const ActionTypeForm = ({ /> )} + {showActionAlertsFilter && ( + <> + {!hideNotifyWhen && } + setActionAlertsFilterProperty('timeframe', timeframe, index)} + /> + + )} {ParamsFieldsComponent ? ( diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx index 7105ab930beb4..c40a4bda55ec7 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx @@ -48,6 +48,7 @@ import { ALERTS_FEATURE_ID, RecoveredActionGroup, isActionGroupDisabledForActionTypeId, + RuleActionAlertsFilterProperty, } from '@kbn/alerting-plugin/common'; import { AlertingConnectorFeatureId } from '@kbn/actions-plugin/common'; import { RuleReducerAction, InitialRule } from './rule_reducer'; @@ -291,6 +292,13 @@ export const RuleForm = ({ [dispatch] ); + const setActionAlertsFilterProperty = useCallback( + (key: string, value: RuleActionAlertsFilterProperty, index: number) => { + dispatch({ command: { type: 'setRuleActionAlertsFilter' }, payload: { key, value, index } }); + }, + [dispatch] + ); + useEffect(() => { const searchValue = searchText ? searchText.trim().toLocaleLowerCase() : null; setFilteredRuleTypes( @@ -677,6 +685,7 @@ export const RuleForm = ({ setActionParamsProperty={setActionParamsProperty} actionTypeRegistry={actionTypeRegistry} setActionFrequencyProperty={setActionFrequencyProperty} + setActionAlertsFilterProperty={setActionAlertsFilterProperty} defaultSummaryMessage={ruleTypeModel?.defaultSummaryMessage || summaryMessage} minimumThrottleInterval={[ruleInterval, ruleIntervalUnit]} /> diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_reducer.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_reducer.ts index 55ce45d592d00..8ac7c38276233 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_reducer.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_reducer.ts @@ -8,7 +8,11 @@ import { SavedObjectAttribute } from '@kbn/core/public'; import { isEqual } from 'lodash'; import { Reducer } from 'react'; -import { RuleActionParam, IntervalSchedule } from '@kbn/alerting-plugin/common'; +import { + RuleActionParam, + IntervalSchedule, + RuleActionAlertsFilterProperty, +} from '@kbn/alerting-plugin/common'; import { Rule, RuleAction } from '../../../types'; import { DEFAULT_FREQUENCY } from '../../../common/constants'; @@ -24,6 +28,7 @@ interface CommandType< | 'setRuleActionParams' | 'setRuleActionProperty' | 'setRuleActionFrequency' + | 'setRuleActionAlertsFilter' > { type: T; } @@ -84,6 +89,10 @@ export type RuleReducerAction = | { command: CommandType<'setRuleActionFrequency'>; payload: Payload; + } + | { + command: CommandType<'setRuleActionAlertsFilter'>; + payload: Payload; }; export type InitialRuleReducer = Reducer<{ rule: InitialRule }, RuleReducerAction>; @@ -215,6 +224,36 @@ export const ruleReducer = ( }; } } + case 'setRuleActionAlertsFilter': { + const { key, value, index } = action.payload as Payload< + keyof RuleAction, + SavedObjectAttribute + >; + if ( + index === undefined || + rule.actions[index] == null || + (!!rule.actions[index][key] && isEqual(rule.actions[index][key], value)) + ) { + return state; + } else { + const oldAction = rule.actions.splice(index, 1)[0]; + const updatedAction = { + ...oldAction, + alertsFilter: { + ...(oldAction.alertsFilter ?? { timeframe: null, query: null }), + [key]: value, + }, + }; + rule.actions.splice(index, 0, updatedAction); + return { + ...state, + rule: { + ...rule, + actions: [...rule.actions], + }, + }; + } + } case 'setRuleActionProperty': { const { key, value, index } = action.payload as RuleActionPayload; if (index === undefined || isEqual(rule.actions[index][key], value)) { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_snooze/recurrence_scheduler/constants.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_snooze/recurrence_scheduler/constants.ts index 72a78dc964225..45b77cb13bcc4 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_snooze/recurrence_scheduler/constants.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_snooze/recurrence_scheduler/constants.ts @@ -6,10 +6,9 @@ */ import { i18n } from '@kbn/i18n'; import { invert, mapValues } from 'lodash'; -import moment from 'moment'; import { RRuleFrequency } from '../../../../../../types'; -export const ISO_WEEKDAYS = [1, 2, 3, 4, 5, 6, 7]; +export { ISO_WEEKDAYS, I18N_WEEKDAY_OPTIONS } from '../../../../../../common/constants'; export const RECURRENCE_END_OPTIONS = [ { id: 'never', label: 'Never' }, @@ -65,11 +64,6 @@ export const DEFAULT_RRULE_PRESETS = { }, }; -export const I18N_WEEKDAY_OPTIONS = ISO_WEEKDAYS.map((n) => ({ - id: String(n), - label: moment().isoWeekday(n).format('dd'), -})); - export const ISO_WEEKDAYS_TO_RRULE: Record = { 1: 'MO', 2: 'TU', diff --git a/x-pack/plugins/triggers_actions_ui/public/common/constants/i18n_weekdays.ts b/x-pack/plugins/triggers_actions_ui/public/common/constants/i18n_weekdays.ts new file mode 100644 index 0000000000000..ad9a72e42016d --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/common/constants/i18n_weekdays.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 { IsoWeekday } from '@kbn/alerting-plugin/common'; +import moment from 'moment'; + +export const ISO_WEEKDAYS: IsoWeekday[] = [1, 2, 3, 4, 5, 6, 7]; + +export const I18N_WEEKDAY_OPTIONS = ISO_WEEKDAYS.map((n) => ({ + id: String(n), + label: moment().isoWeekday(n).format('dd'), +})); + +export const I18N_WEEKDAY_OPTIONS_DDD = ISO_WEEKDAYS.map((n) => ({ + id: String(n), + label: moment().isoWeekday(n).format('ddd'), +})); diff --git a/x-pack/plugins/triggers_actions_ui/public/common/constants/index.ts b/x-pack/plugins/triggers_actions_ui/public/common/constants/index.ts index 33d859b378c17..1d93811d7ecd2 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/constants/index.ts +++ b/x-pack/plugins/triggers_actions_ui/public/common/constants/index.ts @@ -14,3 +14,4 @@ export const VIEW_LICENSE_OPTIONS_LINK = 'https://www.elastic.co/subscriptions'; export const PLUGIN_ID = 'triggersActions'; export const CONNECTORS_PLUGIN_ID = 'triggersActionsConnectors'; +export * from './i18n_weekdays'; From da3c06c447e8873818841bdfea25f492dd03d413 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 11 Apr 2023 20:36:39 +0100 Subject: [PATCH 09/23] skip failing es promotion suites (#154740) --- .../security_solution_endpoint_api_int/apis/index.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/index.ts b/x-pack/test/security_solution_endpoint_api_int/apis/index.ts index de58478d5962d..ea7f71f2d15cc 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/index.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/index.ts @@ -52,9 +52,11 @@ export default function endpointAPIIntegrationTests(providerContext: FtrProvider // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/154740 // loadTestFile(require.resolve('./endpoint_response_actions/execute')); loadTestFile(require.resolve('./file_upload_index')); - loadTestFile(require.resolve('./endpoint_artifacts/trusted_apps')); - loadTestFile(require.resolve('./endpoint_artifacts/event_filters')); - loadTestFile(require.resolve('./endpoint_artifacts/host_isolation_exceptions')); - loadTestFile(require.resolve('./endpoint_artifacts/blocklists')); + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/154740 + // loadTestFile(require.resolve('./endpoint_artifacts/trusted_apps')); + // loadTestFile(require.resolve('./endpoint_artifacts/event_filters')); + // loadTestFile(require.resolve('./endpoint_artifacts/host_isolation_exceptions')); + // loadTestFile(require.resolve('./endpoint_artifacts/blocklists')); + // }); } From 962e91556cb620d27f09b0c9e069593c40456aca Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 11 Apr 2023 20:40:43 +0100 Subject: [PATCH 10/23] skip flaky suite (#154182) --- .../security_solution_endpoint/apps/endpoint/policy_details.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts index da4b754126383..9c59aa319595b 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts @@ -47,7 +47,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); }); - describe('with a valid policy id', () => { + // FLAKY: https://github.com/elastic/kibana/issues/154182 + describe.skip('with a valid policy id', () => { let policyInfo: PolicyTestResourceInfo; before(async () => { From 26f65b3262559a072125ee60017642b1236cdc1d Mon Sep 17 00:00:00 2001 From: Coen Warmer Date: Tue, 11 Apr 2023 21:51:59 +0200 Subject: [PATCH 11/23] [Observability] Add Observability Shared app (#154716) Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .github/CODEOWNERS | 1 + docs/developer/plugin-list.asciidoc | 4 + package.json | 1 + .../styled_components_files.js | 2 +- packages/kbn-optimizer/limits.yml | 1 + tsconfig.base.json | 2 + x-pack/.i18nrc.json | 11 +- .../.storybook/jest_setup.js | 11 + .../observability_shared/.storybook/main.js | 8 + .../.storybook/preview.js | 10 + x-pack/plugins/observability_shared/README.md | 11 + .../observability_shared/common/index.ts | 11 + .../observability_shared/jest.config.js | 18 ++ .../plugins/observability_shared/kibana.jsonc | 15 ++ .../public/components/page_template/README.md | 169 ++++++++++++ .../public/components/page_template/badge.png | Bin 0 -> 10163 bytes .../helpers/navigation_registry.ts | 39 +++ .../public/components/page_template/index.ts | 9 + .../page_template/lazy_page_template.tsx | 26 ++ .../page_template/nav_name_with_badge.tsx | 68 +++++ .../nav_name_with_beta_badge.tsx | 47 ++++ .../page_template/page_template.png | Bin 0 -> 311243 bytes .../page_template/page_template.test.tsx | 121 +++++++++ .../page_template/page_template.tsx | 255 ++++++++++++++++++ .../public/components/tour/index.ts | 8 + .../public/components/tour/steps_config.ts | 125 +++++++++ .../public/components/tour/tour.tsx | 246 +++++++++++++++++ .../observability_shared/public/index.ts | 26 ++ .../observability_shared/public/plugin.ts | 53 ++++ .../update_global_navigation.test.tsx | 236 ++++++++++++++++ .../services/update_global_navigation.tsx | 69 +++++ .../plugins/observability_shared/public/types | 0 .../observability_shared/scripts/storybook.js | 16 ++ .../observability_shared/tsconfig.json | 25 ++ .../observability_shared/typings/common.ts | 18 ++ yarn.lock | 4 + 36 files changed, 1660 insertions(+), 6 deletions(-) create mode 100644 x-pack/plugins/observability_shared/.storybook/jest_setup.js create mode 100644 x-pack/plugins/observability_shared/.storybook/main.js create mode 100644 x-pack/plugins/observability_shared/.storybook/preview.js create mode 100644 x-pack/plugins/observability_shared/README.md create mode 100644 x-pack/plugins/observability_shared/common/index.ts create mode 100644 x-pack/plugins/observability_shared/jest.config.js create mode 100644 x-pack/plugins/observability_shared/kibana.jsonc create mode 100644 x-pack/plugins/observability_shared/public/components/page_template/README.md create mode 100644 x-pack/plugins/observability_shared/public/components/page_template/badge.png create mode 100644 x-pack/plugins/observability_shared/public/components/page_template/helpers/navigation_registry.ts create mode 100644 x-pack/plugins/observability_shared/public/components/page_template/index.ts create mode 100644 x-pack/plugins/observability_shared/public/components/page_template/lazy_page_template.tsx create mode 100644 x-pack/plugins/observability_shared/public/components/page_template/nav_name_with_badge.tsx create mode 100644 x-pack/plugins/observability_shared/public/components/page_template/nav_name_with_beta_badge.tsx create mode 100644 x-pack/plugins/observability_shared/public/components/page_template/page_template.png create mode 100644 x-pack/plugins/observability_shared/public/components/page_template/page_template.test.tsx create mode 100644 x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx create mode 100644 x-pack/plugins/observability_shared/public/components/tour/index.ts create mode 100644 x-pack/plugins/observability_shared/public/components/tour/steps_config.ts create mode 100644 x-pack/plugins/observability_shared/public/components/tour/tour.tsx create mode 100644 x-pack/plugins/observability_shared/public/index.ts create mode 100644 x-pack/plugins/observability_shared/public/plugin.ts create mode 100644 x-pack/plugins/observability_shared/public/services/update_global_navigation.test.tsx create mode 100644 x-pack/plugins/observability_shared/public/services/update_global_navigation.tsx create mode 100644 x-pack/plugins/observability_shared/public/types create mode 100644 x-pack/plugins/observability_shared/scripts/storybook.js create mode 100644 x-pack/plugins/observability_shared/tsconfig.json create mode 100644 x-pack/plugins/observability_shared/typings/common.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a197ebedfd30a..6176200563eab 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -475,6 +475,7 @@ packages/kbn-object-versioning @elastic/appex-sharedux x-pack/packages/observability/alert_details @elastic/actionable-observability x-pack/test/cases_api_integration/common/plugins/observability @elastic/response-ops x-pack/plugins/observability @elastic/actionable-observability +x-pack/plugins/observability_shared @elastic/actionable-observability x-pack/test/security_api_integration/plugins/oidc_provider @elastic/kibana-security test/common/plugins/otel_metrics @elastic/infra-monitoring-ui packages/kbn-optimizer @elastic/kibana-operations diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index 0f284948452c6..572452cec368c 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -641,6 +641,10 @@ Elastic. |This plugin provides shared components and services for use across observability solutions, as well as the observability landing page UI. +|{kib-repo}blob/{branch}/x-pack/plugins/observability_shared/README.md[observabilityShared] +|A plugin that contains components and utilities shared by all Observability plugins. + + |{kib-repo}blob/{branch}/x-pack/plugins/osquery/README.md[osquery] |This plugin adds extended support to Security Solution Fleet Osquery integration diff --git a/package.json b/package.json index 9423330117567..3367b87f74950 100644 --- a/package.json +++ b/package.json @@ -490,6 +490,7 @@ "@kbn/observability-alert-details": "link:x-pack/packages/observability/alert_details", "@kbn/observability-fixtures-plugin": "link:x-pack/test/cases_api_integration/common/plugins/observability", "@kbn/observability-plugin": "link:x-pack/plugins/observability", + "@kbn/observability-shared-plugin": "link:x-pack/plugins/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/osquery-io-ts-types": "link:packages/kbn-osquery-io-ts-types", diff --git a/packages/kbn-babel-preset/styled_components_files.js b/packages/kbn-babel-preset/styled_components_files.js index 9970e587c9b4f..f9b64a5f5804b 100644 --- a/packages/kbn-babel-preset/styled_components_files.js +++ b/packages/kbn-babel-preset/styled_components_files.js @@ -14,7 +14,7 @@ module.exports = { USES_STYLED_COMPONENTS: [ /packages[\/\\](kbn-ui-shared-deps-(npm|src)|kbn-ecs-data-quality-dashboard)[\/\\]/, /src[\/\\]plugins[\/\\](kibana_react)[\/\\]/, - /x-pack[\/\\]plugins[\/\\](apm|beats_management|cases|fleet|infra|lists|observability|exploratory_view|osquery|security_solution|timelines|synthetics|ux)[\/\\]/, + /x-pack[\/\\]plugins[\/\\](apm|beats_management|cases|fleet|infra|lists|observability|observability_shared|exploratory_view|osquery|security_solution|timelines|synthetics|ux)[\/\\]/, /x-pack[\/\\]test[\/\\]plugin_functional[\/\\]plugins[\/\\]resolver_test[\/\\]/, ], }; diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 091b016246911..74d7df9394153 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -94,6 +94,7 @@ pageLoadAssetSize: navigation: 37269 newsfeed: 42228 observability: 95000 + observabilityShared: 21266 osquery: 107090 painlessLab: 179748 presentationUtil: 58834 diff --git a/tsconfig.base.json b/tsconfig.base.json index a141998b3b610..e34bbb2b644a4 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -944,6 +944,8 @@ "@kbn/observability-fixtures-plugin/*": ["x-pack/test/cases_api_integration/common/plugins/observability/*"], "@kbn/observability-plugin": ["x-pack/plugins/observability"], "@kbn/observability-plugin/*": ["x-pack/plugins/observability/*"], + "@kbn/observability-shared-plugin": ["x-pack/plugins/observability_shared"], + "@kbn/observability-shared-plugin/*": ["x-pack/plugins/observability_shared/*"], "@kbn/oidc-provider-plugin": ["x-pack/test/security_api_integration/plugins/oidc_provider"], "@kbn/oidc-provider-plugin/*": ["x-pack/test/security_api_integration/plugins/oidc_provider/*"], "@kbn/open-telemetry-instrumented-plugin": ["test/common/plugins/otel_metrics"], diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 004f8bed6bd58..ff4718c2c7f3a 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -7,6 +7,7 @@ "xpack.stackAlerts": "plugins/stack_alerts", "xpack.stackConnectors": "plugins/stack_connectors", "xpack.apm": "plugins/apm", + "xpack.banners": "plugins/banners", "xpack.canvas": "plugins/canvas", "xpack.cases": "plugins/cases", "xpack.cloud": "plugins/cloud", @@ -47,9 +48,11 @@ "xpack.aiops": ["packages/ml/aiops_components", "plugins/aiops"], "xpack.ml": ["packages/ml/date_picker", "packages/ml/trained_models_utils", "plugins/ml"], "xpack.monitoring": ["plugins/monitoring"], + "xpack.observability": "plugins/observability", + "xpack.observabilityShared": "plugins/observability_shared", "xpack.osquery": ["plugins/osquery"], "xpack.painlessLab": "plugins/painless_lab", - "xpack.profiling": [ "plugins/profiling" ], + "xpack.profiling": ["plugins/profiling"], "xpack.remoteClusters": "plugins/remote_clusters", "xpack.reporting": ["plugins/reporting"], "xpack.rollupJobs": ["plugins/rollup"], @@ -64,6 +67,7 @@ "xpack.spaces": "plugins/spaces", "xpack.savedObjectsTagging": ["plugins/saved_objects_tagging"], "xpack.taskManager": "legacy/plugins/task_manager", + "xpack.threatIntelligence": "plugins/threat_intelligence", "xpack.timelines": "plugins/timelines", "xpack.transform": "plugins/transform", "xpack.triggersActionsUI": "plugins/triggers_actions_ui", @@ -71,10 +75,7 @@ "xpack.synthetics": ["plugins/synthetics"], "xpack.ux": ["plugins/ux"], "xpack.urlDrilldown": "plugins/drilldowns/url_drilldown", - "xpack.watcher": "plugins/watcher", - "xpack.observability": "plugins/observability", - "xpack.banners": "plugins/banners", - "xpack.threatIntelligence": "plugins/threat_intelligence" + "xpack.watcher": "plugins/watcher" }, "exclude": ["examples"], "translations": [ diff --git a/x-pack/plugins/observability_shared/.storybook/jest_setup.js b/x-pack/plugins/observability_shared/.storybook/jest_setup.js new file mode 100644 index 0000000000000..32071b8aa3f62 --- /dev/null +++ b/x-pack/plugins/observability_shared/.storybook/jest_setup.js @@ -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 { setGlobalConfig } from '@storybook/testing-react'; +import * as globalStorybookConfig from './preview'; + +setGlobalConfig(globalStorybookConfig); diff --git a/x-pack/plugins/observability_shared/.storybook/main.js b/x-pack/plugins/observability_shared/.storybook/main.js new file mode 100644 index 0000000000000..86b48c32f103e --- /dev/null +++ b/x-pack/plugins/observability_shared/.storybook/main.js @@ -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. + */ + +module.exports = require('@kbn/storybook').defaultConfig; diff --git a/x-pack/plugins/observability_shared/.storybook/preview.js b/x-pack/plugins/observability_shared/.storybook/preview.js new file mode 100644 index 0000000000000..3200746243d47 --- /dev/null +++ b/x-pack/plugins/observability_shared/.storybook/preview.js @@ -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. + */ + +import { EuiThemeProviderDecorator } from '@kbn/kibana-react-plugin/common'; + +export const decorators = [EuiThemeProviderDecorator]; diff --git a/x-pack/plugins/observability_shared/README.md b/x-pack/plugins/observability_shared/README.md new file mode 100644 index 0000000000000..ee0094851ca16 --- /dev/null +++ b/x-pack/plugins/observability_shared/README.md @@ -0,0 +1,11 @@ +# Observability Shared + +A plugin that contains components and utilities shared by all Observability plugins. + +## Shared navigation + +The Observability plugin maintains a navigation registry for Observability solutions, and exposes a shared page template component. Please refer to the docs in [the component directory](public/components/shared/page_template) for more information on registering your solution's navigation structure, and rendering the navigation via the shared component. + +## A note on cyclical dependencies + +Do not import any Observability plugins into this plugin. Only export shared stuff to other plugins. diff --git a/x-pack/plugins/observability_shared/common/index.ts b/x-pack/plugins/observability_shared/common/index.ts new file mode 100644 index 0000000000000..49ab983118a3b --- /dev/null +++ b/x-pack/plugins/observability_shared/common/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 const observabilityFeatureId = 'observability'; +export const observabilityAppId = 'observability-overview'; +export const casesFeatureId = 'observabilityCases'; +export const sloFeatureId = 'slo'; diff --git a/x-pack/plugins/observability_shared/jest.config.js b/x-pack/plugins/observability_shared/jest.config.js new file mode 100644 index 0000000000000..4820bc69ae4ab --- /dev/null +++ b/x-pack/plugins/observability_shared/jest.config.js @@ -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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../..', + roots: ['/x-pack/plugins/observability_shared'], + setupFiles: ['/x-pack/plugins/observability_shared/.storybook/jest_setup.js'], + coverageDirectory: '/target/kibana-coverage/jest/x-pack/plugins/observability_shared', + coverageReporters: ['text', 'html'], + collectCoverageFrom: [ + '/x-pack/plugins/observability_shared/{common,public,server}/**/*.{js,ts,tsx}', + ], +}; diff --git a/x-pack/plugins/observability_shared/kibana.jsonc b/x-pack/plugins/observability_shared/kibana.jsonc new file mode 100644 index 0000000000000..c89bcf5ddf519 --- /dev/null +++ b/x-pack/plugins/observability_shared/kibana.jsonc @@ -0,0 +1,15 @@ +{ + "type": "plugin", + "id": "@kbn/observability-shared-plugin", + "owner": "@elastic/actionable-observability", + "plugin": { + "id": "observabilityShared", + "server": false, + "browser": true, + "configPath": ["xpack", "observability_shared"], + "requiredPlugins": ["cases", "guidedOnboarding"], + "optionalPlugins": [], + "requiredBundles": ["kibanaReact"], + "extraPublicDirs": ["common"] + } +} diff --git a/x-pack/plugins/observability_shared/public/components/page_template/README.md b/x-pack/plugins/observability_shared/public/components/page_template/README.md new file mode 100644 index 0000000000000..d7ca1a42c3f0c --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/page_template/README.md @@ -0,0 +1,169 @@ +## Overview + +Observability solutions can register their navigation structures via the Observability plugin, this ensures that these navigation options display in the Observability page template component. This is a two part process, A) register your navigation structure and B) consume and render the shared page template component. These two elements are documented below. + +## Navigation registration + +To register a solution's navigation structure you'll first need to ensure your solution has the Shared Observability plugin specified as a dependency in your `kibana.json` file, e.g. + +```json +"requiredPlugins": [ + "sharedObservability" +], +``` + +Now within your solution's **public** plugin `setup` lifecycle method you can +call the `registerSections` method, this will register your solution's specific +navigation structure with the overall Observability navigation registry. + +The `registerSections` function takes an `Observable` of an array of +`NavigationSection`s. Each section can be defined as + +```typescript +export interface NavigationSection { + // the label of the section, should be translated + label: string | undefined; + // the key to sort by in ascending order relative to other entries + sortKey: number; + // the entries to render inside the section + entries: NavigationEntry[]; +} +``` + +Each entry inside of a navigation section is defined as + +```typescript +export interface NavigationEntry { + // the label of the menu entry, should be translated + label: string; + // the kibana app id + app: string; + // the path after the application prefix corresponding to this entry + path: string; + // whether to only match when the full path matches, defaults to `false` + matchFullPath?: boolean; + // whether to ignore trailing slashes, defaults to `true` + ignoreTrailingSlash?: boolean; + // shows NEW badge besides the navigation label, which will automatically disappear when menu item is clicked. + isNewFeature?: boolean; + // shows beta badge lab icon if the feature is still beta besides the navigation label + isBeta?: boolean; +} +``` + +A registration might therefore look like the following: + +```typescript +// x-pack/plugins/example_plugin/public/plugin.ts + +import { of } from 'rxjs'; + +export class Plugin implements PluginClass { + constructor(_context: PluginInitializerContext) {} + + setup(core: CoreSetup, plugins: PluginsSetup) { + plugins.observabilityShared.navigation.registerSections( + of([ + { + label: 'A solution section', + sortKey: 200, + entries: [ + { label: 'Home Page', app: 'exampleA', path: '/', matchFullPath: true }, + { label: 'Example Page', app: 'exampleA', path: '/example' }, + { label: 'Another Example Page', app: 'exampleA', path: '/another-example' }, + ], + }, + { + label: 'Another solution section', + sortKey: 300, + entries: [{ label: 'Example page', app: 'exampleB', path: '/example' }], + }, + ]) + ); + } + + start() {} + + stop() {} +} +``` + +Here `app` would match your solution - e.g. logs, metrics, APM, uptime etc. The registry is fully typed so please refer to the types for specific options. + +Observables are used to facilitate changes over time, for example within the lifetime of your application a license type or set of user permissions may change and as such you may wish to change the navigation structure. If your navigation needs are simple you can pass a value and forget about it. **Solutions are expected to handle their own permissions, and what should or should not be displayed at any time**, the Observability plugin will not add and remove items for you. + +The Observability navigation registry is now aware of your solution's navigation needs ✅ + +## Page template component + +The shared page template component can be used to actually display and render all of the registered navigation structures within your solution. + +The `start` contract of the public Observability plugin exposes a React component, under `navigation.PageTemplate`. + +This can be accessed like so: + +``` +const [coreStart, pluginsStart] = await core.getStartServices(); +const ObservabilityPageTemplate = pluginsStart.observabilityShared.navigation.PageTemplate; +``` + +Now that you have access to the component you can render your solution's content using it. + +```jsx +, + ], + }} +> + // Render anything you like here, this is just an example. + + // Content + + // Content + + +``` + +The `` component is a wrapper around the `` component (which in turn is a wrapper around the `` component). As such the props mostly reflect those available on the wrapped components, again everything is fully typed so please refer to the types for specific options. The `pageSideBar` prop is handled by the component, and will take care of rendering out and managing the items from the registry. + +After these two steps we should see something like the following (note the navigation on the left): + +![Page template rendered example](./page_template.png) + +## Adding NEW badge + +You can add a NEW badge beside the label by using the property `isNewFeature?: boolean;`. + +```js +setup(core: CoreSetup, plugins: PluginsSetup) { + plugins.observabilityShared.navigation.registerSections( + of([ + { + label: 'A solution section', + sortKey: 200, + entries: [ + { label: 'Backends', app: 'exampleA', path: '/example', isNewFeature: true }, + ], + } + ]) + ); + } + +``` + +![NEW Badge example](./badge.png) + +The badge is going to be shown until user clicks on the menu item for the first time. Then we'll save an information at local storage, following this pattern `observability.nav_item_badge_visible_${app}${path}`, the above example would save `observability.nav_item_badge_visible_exampleA/example`. And the badge is removed. It'll only show again if the item saved at local storage is removed or set to `false`. + +It's recommended to remove the badge (e.g. a new feature promotion) in the subsequent release. + +To avoid the navigation flooding with badges, we also want to propose keeping it to maximum 2 active badges for every iteration diff --git a/x-pack/plugins/observability_shared/public/components/page_template/badge.png b/x-pack/plugins/observability_shared/public/components/page_template/badge.png new file mode 100644 index 0000000000000000000000000000000000000000..55ebc28febb4340beb2439dfeeefb5136cd95b09 GIT binary patch literal 10163 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 => void; + sections$: Observable; +} + +export const createNavigationRegistry = (): NavigationRegistry => { + const registeredSections$ = new ReplaySubject>(); + + const registerSections = (sections$: Observable) => { + registeredSections$.next(sections$); + }; + + const sections$: Observable = registeredSections$.pipe( + scan( + (accumulatedSections$, newSections) => accumulatedSections$.add(newSections), + new Set>() + ), + switchMap((registeredSections) => combineLatest([...registeredSections])), + map((registeredSections) => + registeredSections.flat().sort((first, second) => first.sortKey - second.sortKey) + ), + shareReplay(1) + ); + + return { + registerSections, + sections$, + }; +}; diff --git a/x-pack/plugins/observability_shared/public/components/page_template/index.ts b/x-pack/plugins/observability_shared/public/components/page_template/index.ts new file mode 100644 index 0000000000000..5ecb2c493f687 --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/page_template/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 { createLazyObservabilityPageTemplate } from './lazy_page_template'; +export type { LazyObservabilityPageTemplateProps } from './lazy_page_template'; diff --git a/x-pack/plugins/observability_shared/public/components/page_template/lazy_page_template.tsx b/x-pack/plugins/observability_shared/public/components/page_template/lazy_page_template.tsx new file mode 100644 index 0000000000000..7c61cae4f2c73 --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/page_template/lazy_page_template.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 type { + ObservabilityPageTemplateDependencies, + WrappedPageTemplateProps, +} from './page_template'; + +export const LazyObservabilityPageTemplate = React.lazy(() => import('./page_template')); + +export type LazyObservabilityPageTemplateProps = WrappedPageTemplateProps; + +export function createLazyObservabilityPageTemplate( + injectedDeps: ObservabilityPageTemplateDependencies +) { + return (pageTemplateProps: LazyObservabilityPageTemplateProps) => ( + + + + ); +} diff --git a/x-pack/plugins/observability_shared/public/components/page_template/nav_name_with_badge.tsx b/x-pack/plugins/observability_shared/public/components/page_template/nav_name_with_badge.tsx new file mode 100644 index 0000000000000..72d0ac4f93945 --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/page_template/nav_name_with_badge.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { EuiBadge } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import styled from 'styled-components'; + +interface Props { + label: string; + localStorageId: string; +} + +const LabelContainer = styled.span` + max-width: 72%; + float: left; + &:hover, + &:focus { + text-decoration: underline; + } +`; + +const StyledBadge = styled(EuiBadge)` + margin-left: 8px; +`; + +/** + * Gets current state from local storage to show or hide the badge. + * Default value: true + * @param localStorageId + */ +function getBadgeVisibility(localStorageId: string) { + const storedItem = window.localStorage.getItem(localStorageId); + if (storedItem) { + return JSON.parse(storedItem) as boolean; + } + + return true; +} + +/** + * Saves on local storage that this item should no longer be visible + * @param localStorageId + */ +export function hideBadge(localStorageId: string) { + window.localStorage.setItem(localStorageId, JSON.stringify(false)); +} + +export function NavNameWithBadge({ label, localStorageId }: Props) { + const isBadgeVisible = getBadgeVisibility(localStorageId); + return ( + <> + + {label} + + {isBadgeVisible && ( + + {i18n.translate('xpack.observabilityShared.navigation.newBadge', { + defaultMessage: 'NEW', + })} + + )} + + ); +} diff --git a/x-pack/plugins/observability_shared/public/components/page_template/nav_name_with_beta_badge.tsx b/x-pack/plugins/observability_shared/public/components/page_template/nav_name_with_beta_badge.tsx new file mode 100644 index 0000000000000..f9517d92ec574 --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/page_template/nav_name_with_beta_badge.tsx @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiBetaBadge, EuiFlexGroup, EuiFlexItem, IconType } from '@elastic/eui'; + +interface Props { + label?: string; + isTechnicalPreview?: boolean; + iconType?: IconType; +} + +export function NavNameWithBetaBadge({ label, iconType, isTechnicalPreview }: Props) { + return ( + + + + {label} + + + + {isTechnicalPreview ? ( + + ) : ( + + )} + + + ); +} diff --git a/x-pack/plugins/observability_shared/public/components/page_template/page_template.png b/x-pack/plugins/observability_shared/public/components/page_template/page_template.png new file mode 100644 index 0000000000000000000000000000000000000000..7dc88b937c27bf2bb43851d641b4b11213b71045 GIT binary patch literal 311243 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 VXno#evIG2GSGf6~>_3bj{U5)Ckh=f? literal 0 HcmV?d00001 diff --git a/x-pack/plugins/observability_shared/public/components/page_template/page_template.test.tsx b/x-pack/plugins/observability_shared/public/components/page_template/page_template.test.tsx new file mode 100644 index 0000000000000..b33925ed09e4b --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/page_template/page_template.test.tsx @@ -0,0 +1,121 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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 { I18nProvider } from '@kbn/i18n-react'; +import { render } from '@testing-library/react'; +import { shallow } from 'enzyme'; +import React from 'react'; +import { of } from 'rxjs'; +import { getKibanaPageTemplateKibanaDependenciesMock as getPageTemplateServices } from '@kbn/shared-ux-page-kibana-template-mocks'; +import { guidedOnboardingMock } from '@kbn/guided-onboarding-plugin/public/mocks'; + +import { createLazyObservabilityPageTemplate } from './lazy_page_template'; +import { ObservabilityPageTemplate } from './page_template'; +import { createNavigationRegistry } from './helpers/navigation_registry'; + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: () => ({ + pathname: '/test-path', + }), +})); + +const navigationRegistry = createNavigationRegistry(); + +navigationRegistry.registerSections( + of([ + { + label: 'Test A', + sortKey: 100, + entries: [ + { label: 'Section A Url A', app: 'TestA', path: '/url-a' }, + { label: 'Section A Url B', app: 'TestA', path: '/url-b' }, + ], + }, + { + label: 'Test B', + sortKey: 200, + entries: [ + { label: 'Section B Url A', app: 'TestB', path: '/url-a' }, + { label: 'Section B Url B', app: 'TestB', path: '/url-b' }, + ], + }, + ]) +); + +describe('Page template', () => { + it('Provides a working lazy wrapper', () => { + const LazyObservabilityPageTemplate = createLazyObservabilityPageTemplate({ + currentAppId$: of('Test app ID'), + getUrlForApp: () => '/test-url', + navigateToApp: async () => {}, + navigationSections$: navigationRegistry.sections$, + getPageTemplateServices, + guidedOnboardingApi: guidedOnboardingMock.createStart().guidedOnboardingApi, + }); + + const component = shallow( + Test side item], + }} + > +
Test structure
+
+ ); + + expect(component.exists('lazy')).toBe(true); + }); + + it('Utilises the KibanaPageTemplate for rendering', () => { + const component = shallow( + '/test-url'} + navigateToApp={async () => {}} + navigationSections$={navigationRegistry.sections$} + pageHeader={{ + pageTitle: 'Test title', + rightSideItems: [Test side item], + }} + getPageTemplateServices={getPageTemplateServices} + guidedOnboardingApi={guidedOnboardingMock.createStart().guidedOnboardingApi} + > +
Test structure
+
+ ); + + expect(component.is('KibanaPageTemplate')); + }); + + it('Handles outputting the registered navigation structures within a side nav', () => { + const { container } = render( + + '/test-url'} + navigateToApp={async () => {}} + navigationSections$={navigationRegistry.sections$} + pageHeader={{ + pageTitle: 'Test title', + rightSideItems: [Test side item], + }} + getPageTemplateServices={getPageTemplateServices} + guidedOnboardingApi={guidedOnboardingMock.createStart().guidedOnboardingApi} + > +
Test structure
+
+
+ ); + + expect(container).toHaveTextContent('Section A Url A'); + expect(container).toHaveTextContent('Section A Url B'); + expect(container).toHaveTextContent('Section B Url A'); + expect(container).toHaveTextContent('Section B Url B'); + }); +}); diff --git a/x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx b/x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx new file mode 100644 index 0000000000000..696cda97e3e53 --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx @@ -0,0 +1,255 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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 { EuiSideNavItemType, EuiPageSectionProps, EuiErrorBoundary } from '@elastic/eui'; +import { _EuiPageBottomBarProps } from '@elastic/eui/src/components/page_template/bottom_bar/page_bottom_bar'; +import { i18n } from '@kbn/i18n'; +import React, { useMemo } from 'react'; +import { matchPath, useLocation } from 'react-router-dom'; +import useObservable from 'react-use/lib/useObservable'; +import type { Observable } from 'rxjs'; +import type { ApplicationStart } from '@kbn/core/public'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { + KibanaPageTemplate, + KibanaPageTemplateKibanaProvider, +} from '@kbn/shared-ux-page-kibana-template'; +import type { + KibanaPageTemplateProps, + KibanaPageTemplateKibanaDependencies, +} from '@kbn/shared-ux-page-kibana-template'; +import { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public'; +import { ObservabilityTour } from '../tour'; +import { NavNameWithBadge, hideBadge } from './nav_name_with_badge'; +import { NavNameWithBetaBadge } from './nav_name_with_beta_badge'; + +export type WrappedPageTemplateProps = Pick< + KibanaPageTemplateProps, + | 'children' + | 'data-test-subj' + | 'paddingSize' + | 'pageHeader' + | 'restrictWidth' + | 'isEmptyState' + | 'noDataConfig' +> & { + showSolutionNav?: boolean; + isPageDataLoaded?: boolean; + pageSectionProps?: EuiPageSectionProps; + bottomBar?: React.ReactNode; + bottomBarProps?: _EuiPageBottomBarProps; +}; + +export interface NavigationEntry { + // the label of the menu entry, should be translated + label: string; + // the kibana app id + app: string; + // the path after the application prefix corresponding to this entry + path: string; + // whether to only match when the full path matches, defaults to `false` + matchFullPath?: boolean; + // whether to ignore trailing slashes, defaults to `true` + ignoreTrailingSlash?: boolean; + // handler to be called when the item is clicked + onClick?: (event: React.MouseEvent) => void; + // shows NEW badge besides the navigation label, which will automatically disappear when menu item is clicked. + isNewFeature?: boolean; + // shows technical preview lab icon if the feature is still in technical preview besides the navigation label + isTechnicalPreview?: boolean; + // shows beta badge besides the navigation label + isBetaFeature?: boolean; + // override default path matching logic to determine if nav entry is selected + matchPath?: (path: string) => boolean; +} + +export interface NavigationSection { + // the label of the section, should be translated + label: string | undefined; + // the key to sort by in ascending order relative to other entries + sortKey: number; + // the entries to render inside the section + entries: NavigationEntry[]; + // shows beta badge besides the navigation label + isBetaFeature?: boolean; +} + +export interface ObservabilityPageTemplateDependencies { + currentAppId$: Observable; + getUrlForApp: ApplicationStart['getUrlForApp']; + navigateToApp: ApplicationStart['navigateToApp']; + navigationSections$: Observable; + getPageTemplateServices: () => KibanaPageTemplateKibanaDependencies; + guidedOnboardingApi: GuidedOnboardingPluginStart['guidedOnboardingApi']; +} + +export type ObservabilityPageTemplateProps = ObservabilityPageTemplateDependencies & + WrappedPageTemplateProps; + +export function ObservabilityPageTemplate({ + children, + currentAppId$, + getUrlForApp, + navigateToApp, + navigationSections$, + showSolutionNav = true, + isPageDataLoaded = true, + getPageTemplateServices, + bottomBar, + bottomBarProps, + pageSectionProps, + guidedOnboardingApi, + ...pageTemplateProps +}: ObservabilityPageTemplateProps): React.ReactElement | null { + const sections = useObservable(navigationSections$, []); + const currentAppId = useObservable(currentAppId$, undefined); + const { pathname: currentPath } = useLocation(); + + const { services } = useKibana(); + + const sideNavItems = useMemo>>( + () => + sections.map(({ label, entries, isBetaFeature }, sectionIndex) => ({ + id: `${sectionIndex}`, + name: isBetaFeature ? : label, + items: entries.map((entry, entryIndex) => { + const href = getUrlForApp(entry.app, { + path: entry.path, + }); + + const isSelected = + entry.app === currentAppId && + (entry.matchPath + ? entry.matchPath(currentPath) + : matchPath(currentPath, { + path: entry.path, + exact: !!entry.matchFullPath, + strict: !entry.ignoreTrailingSlash, + }) != null); + const badgeLocalStorageId = `observability.nav_item_badge_visible_${entry.app}${entry.path}`; + const navId = entry.label.toLowerCase().split(' ').join('_'); + return { + id: `${sectionIndex}.${entryIndex}`, + name: entry.isBetaFeature ? ( + + ) : entry.isNewFeature ? ( + + ) : entry.isTechnicalPreview ? ( + + ) : ( + entry.label + ), + href, + isSelected, + 'data-nav-id': navId, + 'data-test-subj': `observability-nav-${entry.app}-${navId}`, + onClick: (event) => { + if (entry.onClick) { + entry.onClick(event); + } + + // Hides NEW badge when the item is clicked + if (entry.isNewFeature) { + hideBadge(badgeLocalStorageId); + } + + if ( + event.button !== 0 || + event.defaultPrevented || + event.metaKey || + event.altKey || + event.ctrlKey || + event.shiftKey + ) { + return; + } + + event.preventDefault(); + navigateToApp(entry.app, { + path: entry.path, + }); + }, + }; + }), + })), + [currentAppId, currentPath, getUrlForApp, navigateToApp, sections] + ); + + return ( + + + {({ isTourVisible }) => { + return ( + + + + {children} + + + {bottomBar && ( + + {bottomBar} + + )} + + ); + }} + + + ); +} + +// for lazy import +// eslint-disable-next-line import/no-default-export +export default ObservabilityPageTemplate; + +const sideNavTitle = i18n.translate('xpack.observabilityShared.pageLayout.sideNavTitle', { + defaultMessage: 'Observability', +}); + +export const LazyObservabilityPageTemplate = React.lazy(() => import('./page_template')); + +export type LazyObservabilityPageTemplateProps = WrappedPageTemplateProps; + +export function createLazyObservabilityPageTemplate( + injectedDeps: ObservabilityPageTemplateDependencies +) { + return (pageTemplateProps: LazyObservabilityPageTemplateProps) => ( + + + + ); +} diff --git a/x-pack/plugins/observability_shared/public/components/tour/index.ts b/x-pack/plugins/observability_shared/public/components/tour/index.ts new file mode 100644 index 0000000000000..45449abf3ed5a --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/tour/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 { ObservabilityTour, observTourStepStorageKey, useObservabilityTourContext } from './tour'; diff --git a/x-pack/plugins/observability_shared/public/components/tour/steps_config.ts b/x-pack/plugins/observability_shared/public/components/tour/steps_config.ts new file mode 100644 index 0000000000000..5555a81813b40 --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/tour/steps_config.ts @@ -0,0 +1,125 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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 { EuiTourStepProps, ElementTarget } from '@elastic/eui'; + +interface TourStep { + content: string; + anchor: ElementTarget; + anchorPosition: EuiTourStepProps['anchorPosition']; + title: EuiTourStepProps['title']; + dataTestSubj: string; + offset?: number; + imageConfig?: { + name: string; + altText: string; + }; +} + +export const tourStepsConfig: TourStep[] = [ + { + title: i18n.translate('xpack.observabilityShared.tour.observabilityOverviewStep.tourTitle', { + defaultMessage: 'Welcome to Elastic Observability', + }), + content: i18n.translate( + 'xpack.observabilityShared.tour.observabilityOverviewStep.tourContent', + { + defaultMessage: + 'Take a quick tour to learn the benefits of having all of your observability data in one stack.', + } + ), + anchor: `[id^="SolutionNav"]`, + anchorPosition: 'rightUp', + dataTestSubj: 'overviewStep', + }, + { + title: i18n.translate('xpack.observabilityShared.tour.streamStep.tourTitle', { + defaultMessage: 'Tail your logs in real time', + }), + content: i18n.translate('xpack.observabilityShared.tour.streamStep.tourContent', { + defaultMessage: + 'Monitor, filter, and inspect log events flowing in from your applications, servers, virtual machines, and containers.', + }), + anchor: `[data-nav-id="stream"]`, + anchorPosition: 'rightUp', + dataTestSubj: 'streamStep', + imageConfig: { + name: 'onboarding_tour_step_logs.gif', + altText: i18n.translate('xpack.observabilityShared.tour.streamStep.imageAltText', { + defaultMessage: 'Logs stream demonstration', + }), + }, + }, + { + title: i18n.translate('xpack.observabilityShared.tour.metricsExplorerStep.tourTitle', { + defaultMessage: 'Monitor your infrastructure health', + }), + content: i18n.translate('xpack.observabilityShared.tour.metricsExplorerStep.tourContent', { + defaultMessage: + 'Stream, group, and visualize metrics from your systems, cloud, network, and other infrastructure sources.', + }), + anchor: `[data-nav-id="metrics_explorer"]`, + anchorPosition: 'rightUp', + dataTestSubj: 'metricsExplorerStep', + imageConfig: { + name: 'onboarding_tour_step_metrics.gif', + altText: i18n.translate('xpack.observabilityShared.tour.metricsExplorerStep.imageAltText', { + defaultMessage: 'Metrics explorer demonstration', + }), + }, + }, + { + title: i18n.translate('xpack.observabilityShared.tour.servicesStep.tourTitle', { + defaultMessage: 'Identify and resolve application issues', + }), + content: i18n.translate('xpack.observabilityShared.tour.servicesStep.tourContent', { + defaultMessage: + 'Find and fix performance problems quickly by collecting detailed information about your services.', + }), + anchor: `[data-nav-id="services"]`, + anchorPosition: 'rightUp', + dataTestSubj: 'servicesStep', + imageConfig: { + name: 'onboarding_tour_step_services.gif', + altText: i18n.translate('xpack.observabilityShared.tour.servicesStep.imageAltText', { + defaultMessage: 'Services demonstration', + }), + }, + }, + { + title: i18n.translate('xpack.observabilityShared.tour.alertsStep.tourTitle', { + defaultMessage: 'Get notified when something changes', + }), + content: i18n.translate('xpack.observabilityShared.tour.alertsStep.tourContent', { + defaultMessage: + 'Define and detect conditions that trigger alerts with third-party platform integrations like email, PagerDuty, and Slack.', + }), + anchor: `[data-nav-id="alerts"]`, + anchorPosition: 'rightUp', + dataTestSubj: 'alertStep', + imageConfig: { + name: 'onboarding_tour_step_alerts.gif', + altText: i18n.translate('xpack.observabilityShared.tour.alertsStep.imageAltText', { + defaultMessage: 'Alerts demonstration', + }), + }, + }, + { + title: i18n.translate('xpack.observabilityShared.tour.guidedSetupStep.tourTitle', { + defaultMessage: 'Do more with Elastic Observability', + }), + content: i18n.translate('xpack.observabilityShared.tour.guidedSetupStep.tourContent', { + defaultMessage: + 'The easiest way to continue with Elastic Observability is to follow recommended next steps in the data assistant.', + }), + anchor: '#guidedSetupButton', + anchorPosition: 'rightUp', + dataTestSubj: 'guidedSetupStep', + offset: 10, + }, +]; diff --git a/x-pack/plugins/observability_shared/public/components/tour/tour.tsx b/x-pack/plugins/observability_shared/public/components/tour/tour.tsx new file mode 100644 index 0000000000000..49083bf307e31 --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/tour/tour.tsx @@ -0,0 +1,246 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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, { + ReactNode, + useState, + useCallback, + useEffect, + createContext, + useContext, +} from 'react'; + +import { i18n } from '@kbn/i18n'; +import { + EuiButton, + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiTourStep, + EuiTourStepProps, + EuiImage, + EuiSpacer, + EuiText, + useIsWithinBreakpoints, +} from '@elastic/eui'; +import { useLocation } from 'react-router-dom'; +import { ApplicationStart } from '@kbn/core/public'; +import useObservable from 'react-use/lib/useObservable'; +import { of } from 'rxjs'; +import type { GuidedOnboardingApi } from '@kbn/guided-onboarding-plugin/public/types'; +import { observabilityAppId } from '../../../common'; +import { tourStepsConfig } from './steps_config'; + +const minWidth: EuiTourStepProps['minWidth'] = 360; +const maxWidth: EuiTourStepProps['maxWidth'] = 360; +const offset: EuiTourStepProps['offset'] = 30; +const repositionOnScroll: EuiTourStepProps['repositionOnScroll'] = true; + +const overviewPath = '/overview'; +const dataAssistantStep = 6; + +export const observTourStepStorageKey = 'guidedOnboarding.observability.tourStep'; + +const getSteps = ({ + activeStep, + incrementStep, + endTour, + prependBasePath, +}: { + activeStep: number; + incrementStep: () => void; + endTour: () => void; + prependBasePath?: (imageName: string) => string; +}) => { + const footerAction = ( + + + endTour()} + size="xs" + color="text" + // Used for testing and to track FS usage + data-test-subj="onboarding--observTourSkipButton" + > + {i18n.translate('xpack.observabilityShared.tour.skipButtonLabel', { + defaultMessage: 'Skip tour', + })} + + + + incrementStep()} + size="s" + color="success" + // Used for testing and to track FS usage + data-test-subj="onboarding--observTourNextStepButton" + > + {i18n.translate('xpack.observabilityShared.tour.nextButtonLabel', { + defaultMessage: 'Next', + })} + + + + ); + + const lastStepFooterAction = ( + // data-test-subj is used for testing and to track FS usage + endTour()} + data-test-subj="onboarding--observTourEndButton" + > + {i18n.translate('xpack.observabilityShared.tour.endButtonLabel', { + defaultMessage: 'End tour', + })} + + ); + + return tourStepsConfig.map((stepConfig, index) => { + const step = index + 1; + const { dataTestSubj, content, offset: stepOffset, imageConfig, ...tourStepProps } = stepConfig; + return ( + endTour()} + footerAction={activeStep === tourStepsConfig.length ? lastStepFooterAction : footerAction} + panelProps={{ + 'data-test-subj': dataTestSubj, + }} + content={ + <> + +

{content}

+
+ {imageConfig && prependBasePath && ( + <> + + + + )} + + } + /> + ); + }); +}; + +export interface ObservabilityTourContextValue { + endTour: () => void; + isTourVisible: boolean; +} + +const ObservabilityTourContext = createContext({ + endTour: () => {}, + isTourVisible: false, +} as ObservabilityTourContextValue); + +export function ObservabilityTour({ + children, + navigateToApp, + isPageDataLoaded, + showTour, + prependBasePath, + guidedOnboardingApi, +}: { + children: ({ isTourVisible }: { isTourVisible: boolean }) => ReactNode; + navigateToApp: ApplicationStart['navigateToApp']; + isPageDataLoaded: boolean; + showTour: boolean; + prependBasePath?: (imageName: string) => string; + guidedOnboardingApi?: GuidedOnboardingApi; +}) { + const prevActiveStep = localStorage.getItem(observTourStepStorageKey); + const initialActiveStep = prevActiveStep === null ? 1 : Number(prevActiveStep); + + const isGuidedOnboardingActive = useObservable( + // if guided onboarding is not available, return false + guidedOnboardingApi + ? guidedOnboardingApi.isGuideStepActive$('kubernetes', 'tour_observability') + : of(false) + ); + + const [isTourActive, setIsTourActive] = useState(false); + const [activeStep, setActiveStep] = useState(initialActiveStep); + + const { pathname: currentPath } = useLocation(); + + const isSmallBreakpoint = useIsWithinBreakpoints(['s']); + + const isOverviewPage = currentPath === overviewPath; + + const incrementStep = useCallback(() => { + setActiveStep((prevState) => prevState + 1); + }, []); + + const endTour = useCallback(async () => { + // Mark the onboarding guide step as complete + if (guidedOnboardingApi) { + await guidedOnboardingApi.completeGuideStep('kubernetes', 'tour_observability'); + } + // Reset EuiTour step state + setActiveStep(1); + }, [guidedOnboardingApi]); + + /** + * The tour should only be visible if the following conditions are met: + * - Only pages with the side nav should show the tour (showTour === true) + * - Tour is set to active per the guided onboarding service (isTourActive === true) + * - Any page data must be loaded in order for the tour to render correctly + * - The tour should only render on medium-large screens + */ + const isTourVisible = showTour && isTourActive && isPageDataLoaded && isSmallBreakpoint === false; + + const context: ObservabilityTourContextValue = { endTour, isTourVisible }; + + useEffect(() => { + localStorage.setItem(observTourStepStorageKey, String(activeStep)); + }, [activeStep]); + + useEffect(() => { + setIsTourActive(Boolean(isGuidedOnboardingActive)); + }, [isGuidedOnboardingActive]); + + useEffect(() => { + // The user must be on the overview page to view the data assistant step in the tour + if (isTourActive && isOverviewPage === false && activeStep === dataAssistantStep) { + navigateToApp(observabilityAppId, { + path: overviewPath, + }); + } + }, [activeStep, isOverviewPage, isTourActive, navigateToApp]); + + return ( + + <> + {children({ isTourVisible })} + {isTourVisible && getSteps({ activeStep, incrementStep, endTour, prependBasePath })} + + + ); +} + +export const useObservabilityTourContext = (): ObservabilityTourContextValue => { + const ctx = useContext(ObservabilityTourContext); + if (!ctx) { + throw new Error('useObservabilityTourContext can only be called inside of TourContext'); + } + return ctx; +}; diff --git a/x-pack/plugins/observability_shared/public/index.ts b/x-pack/plugins/observability_shared/public/index.ts new file mode 100644 index 0000000000000..ecb2095e4eb6f --- /dev/null +++ b/x-pack/plugins/observability_shared/public/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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ObservabilitySharedPlugin } from './plugin'; +export type { + ObservabilitySharedPlugin, + ObservabilitySharedPluginSetup, + ObservabilitySharedPluginStart, +} from './plugin'; + +export type { + ObservabilityPageTemplateProps, + LazyObservabilityPageTemplateProps, +} from './components/page_template/page_template'; + +export type { NavigationEntry } from './components/page_template/page_template'; + +export const plugin = () => { + return new ObservabilitySharedPlugin(); +}; + +export { observabilityFeatureId, casesFeatureId, sloFeatureId } from '../common'; diff --git a/x-pack/plugins/observability_shared/public/plugin.ts b/x-pack/plugins/observability_shared/public/plugin.ts new file mode 100644 index 0000000000000..527d33e8a502e --- /dev/null +++ b/x-pack/plugins/observability_shared/public/plugin.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { CoreStart, Plugin } from '@kbn/core/public'; +import type { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public'; +import { createNavigationRegistry } from './components/page_template/helpers/navigation_registry'; +import { createLazyObservabilityPageTemplate } from './components/page_template'; +import { updateGlobalNavigation } from './services/update_global_navigation'; + +export interface ObservabilitySharedStart { + guidedOnboarding: GuidedOnboardingPluginStart; +} + +export type ObservabilitySharedPluginSetup = ReturnType; +export type ObservabilitySharedPluginStart = ReturnType; + +export class ObservabilitySharedPlugin implements Plugin { + private readonly navigationRegistry = createNavigationRegistry(); + + public setup() { + return { + navigation: { + registerSections: this.navigationRegistry.registerSections, + }, + }; + } + + public start(core: CoreStart, plugins: ObservabilitySharedStart) { + const { application } = core; + + const PageTemplate = createLazyObservabilityPageTemplate({ + currentAppId$: application.currentAppId$, + getUrlForApp: application.getUrlForApp, + navigateToApp: application.navigateToApp, + navigationSections$: this.navigationRegistry.sections$, + guidedOnboardingApi: plugins.guidedOnboarding.guidedOnboardingApi, + getPageTemplateServices: () => ({ coreStart: core }), + }); + + return { + navigation: { + PageTemplate, + }, + updateGlobalNavigation, + }; + } + + public stop() {} +} diff --git a/x-pack/plugins/observability_shared/public/services/update_global_navigation.test.tsx b/x-pack/plugins/observability_shared/public/services/update_global_navigation.test.tsx new file mode 100644 index 0000000000000..cc908f6b3d108 --- /dev/null +++ b/x-pack/plugins/observability_shared/public/services/update_global_navigation.test.tsx @@ -0,0 +1,236 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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 { Subject } from 'rxjs'; +import { App, AppDeepLink, ApplicationStart, AppNavLinkStatus, AppUpdater } from '@kbn/core/public'; +import { casesFeatureId, sloFeatureId } from '../../common'; +import { updateGlobalNavigation } from './update_global_navigation'; + +// Used in updater callback +const app = {} as unknown as App; + +describe('updateGlobalNavigation', () => { + describe('when no observability apps are enabled', () => { + it('hides the overview link', () => { + const capabilities = { + navLinks: { apm: false, logs: false, metrics: false, uptime: false }, + } as unknown as ApplicationStart['capabilities']; + const deepLinks: AppDeepLink[] = []; + const callback = jest.fn(); + const updater$ = { + next: (cb: AppUpdater) => callback(cb(app)), + } as unknown as Subject; + + updateGlobalNavigation({ capabilities, deepLinks, updater$ }); + + expect(callback).toHaveBeenCalledWith({ + deepLinks, + navLinkStatus: AppNavLinkStatus.hidden, + }); + }); + }); + + describe('when one observability app is enabled', () => { + it('shows the overview link', () => { + const capabilities = { + navLinks: { apm: true, logs: false, metrics: false, uptime: false }, + } as unknown as ApplicationStart['capabilities']; + const deepLinks: AppDeepLink[] = []; + const callback = jest.fn(); + const updater$ = { + next: (cb: AppUpdater) => callback(cb(app)), + } as unknown as Subject; + + updateGlobalNavigation({ capabilities, deepLinks, updater$ }); + + expect(callback).toHaveBeenCalledWith({ + deepLinks, + navLinkStatus: AppNavLinkStatus.visible, + }); + }); + + describe('when cases are enabled', () => { + it('shows the cases deep link', () => { + const capabilities = { + [casesFeatureId]: { read_cases: true }, + navLinks: { apm: true, logs: false, metrics: false, uptime: false }, + } as unknown as ApplicationStart['capabilities']; + + const caseRoute = { + id: 'cases', + title: 'Cases', + order: 8003, + path: '/cases', + navLinkStatus: AppNavLinkStatus.hidden, + }; + + const deepLinks = [caseRoute]; + + const callback = jest.fn(); + const updater$ = { + next: (cb: AppUpdater) => callback(cb(app)), + } as unknown as Subject; + + updateGlobalNavigation({ capabilities, deepLinks, updater$ }); + + expect(callback).toHaveBeenCalledWith({ + deepLinks: [ + { + ...caseRoute, + navLinkStatus: AppNavLinkStatus.visible, + }, + ], + navLinkStatus: AppNavLinkStatus.visible, + }); + }); + }); + + describe('with no case read capabilities', () => { + it('hides the cases deep link', () => { + const capabilities = { + [casesFeatureId]: { read_cases: false }, + navLinks: { apm: true, logs: false, metrics: false, uptime: false }, + } as unknown as ApplicationStart['capabilities']; + + const caseRoute = { + id: 'cases', + title: 'Cases', + order: 8003, + path: '/cases', + navLinkStatus: AppNavLinkStatus.hidden, + }; + + const deepLinks = [caseRoute]; + + const callback = jest.fn(); + const updater$ = { + next: (cb: AppUpdater) => callback(cb(app)), + } as unknown as Subject; + + updateGlobalNavigation({ capabilities, deepLinks, updater$ }); + + expect(callback).toHaveBeenCalledWith({ + deepLinks: [ + { + ...caseRoute, + navLinkStatus: AppNavLinkStatus.hidden, + }, + ], + navLinkStatus: AppNavLinkStatus.visible, + }); + }); + }); + + describe('when alerts are enabled', () => { + it('shows the alerts deep link', () => { + const capabilities = { + [casesFeatureId]: { read_cases: true }, + navLinks: { apm: true, logs: false, metrics: false, uptime: false }, + } as unknown as ApplicationStart['capabilities']; + + const deepLinks = [ + { + id: 'alerts', + title: 'Alerts', + order: 8001, + path: '/alerts', + navLinkStatus: AppNavLinkStatus.hidden, + }, + ]; + const callback = jest.fn(); + const updater$ = { + next: (cb: AppUpdater) => callback(cb(app)), + } as unknown as Subject; + + updateGlobalNavigation({ capabilities, deepLinks, updater$ }); + + expect(callback).toHaveBeenCalledWith({ + deepLinks: [ + { + id: 'alerts', + title: 'Alerts', + order: 8001, + path: '/alerts', + navLinkStatus: AppNavLinkStatus.visible, + }, + ], + navLinkStatus: AppNavLinkStatus.visible, + }); + }); + }); + + it("hides the slo link when the capabilities don't include it", () => { + const capabilities = { + navLinks: { apm: true, logs: false, metrics: false, uptime: false }, + } as unknown as ApplicationStart['capabilities']; + + const sloRoute = { + id: 'slos', + title: 'SLOs', + order: 8002, + path: '/slos', + navLinkStatus: AppNavLinkStatus.hidden, + }; + + const deepLinks = [sloRoute]; + + const callback = jest.fn(); + const updater$ = { + next: (cb: AppUpdater) => callback(cb(app)), + } as unknown as Subject; + + updateGlobalNavigation({ capabilities, deepLinks, updater$ }); + + expect(callback).toHaveBeenCalledWith({ + deepLinks: [ + { + ...sloRoute, + navLinkStatus: AppNavLinkStatus.hidden, + }, + ], + navLinkStatus: AppNavLinkStatus.visible, + }); + }); + + describe('when slos are enabled', () => { + it('shows the slos deep link', () => { + const capabilities = { + [casesFeatureId]: { read_cases: true }, + [sloFeatureId]: { read: true }, + navLinks: { apm: false, logs: false, metrics: false, uptime: false }, + } as unknown as ApplicationStart['capabilities']; + + const sloRoute = { + id: 'slos', + title: 'SLOs', + order: 8002, + path: '/slos', + navLinkStatus: AppNavLinkStatus.hidden, + }; + + const deepLinks = [sloRoute]; + + const callback = jest.fn(); + const updater$ = { + next: (cb: AppUpdater) => callback(cb(app)), + } as unknown as Subject; + + updateGlobalNavigation({ capabilities, deepLinks, updater$ }); + + expect(callback).toHaveBeenCalledWith({ + deepLinks: [ + { + ...sloRoute, + navLinkStatus: AppNavLinkStatus.visible, + }, + ], + navLinkStatus: AppNavLinkStatus.visible, + }); + }); + }); + }); +}); diff --git a/x-pack/plugins/observability_shared/public/services/update_global_navigation.tsx b/x-pack/plugins/observability_shared/public/services/update_global_navigation.tsx new file mode 100644 index 0000000000000..8908a90ff6545 --- /dev/null +++ b/x-pack/plugins/observability_shared/public/services/update_global_navigation.tsx @@ -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 { Subject } from 'rxjs'; +import { AppNavLinkStatus, AppUpdater, ApplicationStart, AppDeepLink } from '@kbn/core/public'; +import { CasesDeepLinkId } from '@kbn/cases-plugin/public'; +import { casesFeatureId, sloFeatureId } from '../../common'; + +export function updateGlobalNavigation({ + capabilities, + deepLinks, + updater$, +}: { + capabilities: ApplicationStart['capabilities']; + deepLinks: AppDeepLink[]; + updater$: Subject; +}) { + const { apm, logs, metrics, uptime } = capabilities.navLinks; + const someVisible = Object.values({ + apm, + logs, + metrics, + uptime, + }).some((visible) => visible); + + const updatedDeepLinks = deepLinks.map((link) => { + switch (link.id) { + case CasesDeepLinkId.cases: + return { + ...link, + navLinkStatus: + capabilities[casesFeatureId].read_cases && someVisible + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }; + case 'alerts': + return { + ...link, + navLinkStatus: someVisible ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden, + }; + case 'rules': + return { + ...link, + navLinkStatus: someVisible ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden, + }; + case 'slos': + return { + ...link, + navLinkStatus: !!capabilities[sloFeatureId]?.read + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }; + default: + return link; + } + }); + + updater$.next(() => ({ + deepLinks: updatedDeepLinks, + navLinkStatus: + someVisible || !!capabilities[sloFeatureId]?.read + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + })); +} diff --git a/x-pack/plugins/observability_shared/public/types b/x-pack/plugins/observability_shared/public/types new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/x-pack/plugins/observability_shared/scripts/storybook.js b/x-pack/plugins/observability_shared/scripts/storybook.js new file mode 100644 index 0000000000000..92dc702569caa --- /dev/null +++ b/x-pack/plugins/observability_shared/scripts/storybook.js @@ -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 { join } from 'path'; + +require('@kbn/storybook').runStorybookCli({ + name: 'observabilityShared', + storyGlobs: [ + join(__dirname, '..', 'public', 'components', '**', '*.stories.tsx'), + join(__dirname, '..', 'public', 'pages', '**', '*.stories.tsx'), + ], +}); diff --git a/x-pack/plugins/observability_shared/tsconfig.json b/x-pack/plugins/observability_shared/tsconfig.json new file mode 100644 index 0000000000000..fba33ee93d5f4 --- /dev/null +++ b/x-pack/plugins/observability_shared/tsconfig.json @@ -0,0 +1,25 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": [ + "common/**/*", + "public/**/*", + "public/**/*.json", + "server/**/*", + "typings/**/*", + "../../../typings/**/*" + ], + "kbn_references": [ + "@kbn/core", + "@kbn/kibana-react-plugin", + "@kbn/cases-plugin", + "@kbn/guided-onboarding-plugin", + "@kbn/i18n", + "@kbn/shared-ux-page-kibana-template", + "@kbn/i18n-react", + "@kbn/shared-ux-page-kibana-template-mocks", + ], + "exclude": ["target/**/*"] +} diff --git a/x-pack/plugins/observability_shared/typings/common.ts b/x-pack/plugins/observability_shared/typings/common.ts new file mode 100644 index 0000000000000..fcfd5db7dcbd9 --- /dev/null +++ b/x-pack/plugins/observability_shared/typings/common.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. + */ + +export type ObservabilityApp = + | 'infra_metrics' + | 'infra_logs' + | 'apm' + // we will remove uptime in future to replace to be replace by synthetics + | 'uptime' + | 'synthetics' + | 'observability-overview' + | 'stack_monitoring' + | 'ux' + | 'fleet'; diff --git a/yarn.lock b/yarn.lock index 48bd72635353d..6bb7bbe5c9842 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4625,6 +4625,10 @@ version "0.0.0" uid "" +"@kbn/observability-shared-plugin@link:x-pack/plugins/observability_shared": + version "0.0.0" + uid "" + "@kbn/oidc-provider-plugin@link:x-pack/test/security_api_integration/plugins/oidc_provider": version "0.0.0" uid "" From d2f7860cff0e38118989355a8da821ba8f9ef8a5 Mon Sep 17 00:00:00 2001 From: Adam Demjen Date: Tue, 11 Apr 2023 16:02:37 -0400 Subject: [PATCH 12/23] [ML Inference] Multi-field selector for ELSER (#154598) ## Summary This PR adds UI components for creating multiple field mappings for an inference pipeline. In the field configuration step existing source fields can be selected from the mapping, or non-existent fields can be typed in. Clicking the Add button sets the mapping; the target field name is derived from the source field name as `ml.inference._expanded`. The selected mappings are listed in a table on the same screen. The trashcan icon can be used to remove a mapping. This field configuration screen only shows if an ELSER model was selected for the pipeline. For any other model types the classic "single source and target field" screen is shown (the target field can be set by the user). Attaching an existing ELSER pipeline is disabled - supporting this will be in scope for a separate PR. I also added the logic to modify the pipeline generator logic in case multiple field mappings are selected. In this case a `remove` and an `inference` processor are generated for each selected mapping. ![Screenshot 2023-04-10 at 5 46 24 PM](https://user-images.githubusercontent.com/14224983/231008803-26a0c5ba-748d-4377-87c5-a40717426c4c.png) ![Screenshot 2023-04-10 at 5 46 34 PM](https://user-images.githubusercontent.com/14224983/231008804-a6f7e508-afcd-4227-87cb-9fac5f607132.png) ![Screenshot 2023-04-10 at 5 46 44 PM](https://user-images.githubusercontent.com/14224983/231008805-0ba61948-c8b6-411a-8969-f6aeaa820c39.png) ![Screenshot 2023-04-10 at 6 01 55 PM](https://user-images.githubusercontent.com/14224983/231008808-70ab3b10-dab6-41aa-a2e6-e46bdc259ca3.png) ### Checklist Delete any items that are not applicable to this PR. - [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> --- .../ml_inference_pipeline/index.test.ts | 56 ++++ .../common/ml_inference_pipeline/index.ts | 119 +++++---- .../ml_inference/configure_fields.test.tsx | 42 +++ .../ml_inference/configure_fields.tsx | 154 ++--------- .../ml_inference/configure_pipeline.tsx | 1 + .../ml_inference/ml_inference_logic.ts | 79 +++++- .../multi_field_selector.test.tsx | 129 +++++++++ .../ml_inference/multi_field_selector.tsx | 245 ++++++++++++++++++ .../ml_inference/pipeline_select_option.tsx | 8 +- .../single_field_selector.test.tsx | 87 +++++++ .../ml_inference/single_field_selector.tsx | 145 +++++++++++ .../pipelines/ml_inference/test_pipeline.tsx | 1 - .../pipelines/ml_inference/types.ts | 3 + .../pipelines/ml_inference/utils.ts | 34 +++ 14 files changed, 904 insertions(+), 199 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_fields.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/multi_field_selector.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/multi_field_selector.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/single_field_selector.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/single_field_selector.tsx diff --git a/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.test.ts b/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.test.ts index 0d9a668b2a6f0..20c5ce358d7ca 100644 --- a/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.test.ts +++ b/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.test.ts @@ -231,6 +231,62 @@ describe('generateMlInferencePipelineBody lib function', () => { }) ); }); + + it('should return something expected with multiple fields', () => { + const actual: MlInferencePipeline = generateMlInferencePipelineBody({ + description: 'my-description', + model: mockModel, + pipelineName: 'my-pipeline', + fieldMappings: [ + { sourceField: 'my-source-field1', targetField: 'my-destination-field1' }, + { sourceField: 'my-source-field2', targetField: 'my-destination-field2' }, + { sourceField: 'my-source-field3', targetField: 'my-destination-field3' }, + ], + }); + + expect(actual).toEqual( + expect.objectContaining({ + processors: expect.arrayContaining([ + { + remove: expect.objectContaining({ + field: 'ml.inference.my-destination-field1', + }), + }, + { + remove: expect.objectContaining({ + field: 'ml.inference.my-destination-field2', + }), + }, + { + remove: expect.objectContaining({ + field: 'ml.inference.my-destination-field3', + }), + }, + { + inference: expect.objectContaining({ + field_map: { + 'my-source-field1': 'MODEL_INPUT_FIELD', + }, + }), + }, + { + inference: expect.objectContaining({ + field_map: { + 'my-source-field2': 'MODEL_INPUT_FIELD', + }, + }), + }, + { + inference: expect.objectContaining({ + field_map: { + 'my-source-field3': 'MODEL_INPUT_FIELD', + }, + }), + }, + ]), + }) + ); + }); }); describe('parseMlInferenceParametersFromPipeline', () => { diff --git a/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.ts b/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.ts index 1520d3ea1fd8f..0c56f7dd373f6 100644 --- a/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.ts +++ b/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.ts @@ -6,6 +6,7 @@ */ import { + IngestInferenceProcessor, IngestPipeline, IngestRemoveProcessor, IngestSetProcessor, @@ -54,67 +55,93 @@ export const generateMlInferencePipelineBody = ({ model, pipelineName, }: MlInferencePipelineParams): MlInferencePipeline => { - // if model returned no input field, insert a placeholder - const modelInputField = - model.input?.field_names?.length > 0 ? model.input.field_names[0] : 'MODEL_INPUT_FIELD'; - - // For now this only works for a single field mapping - const sourceField = fieldMappings[0].sourceField; - const targetField = fieldMappings[0].targetField; const inferenceType = Object.keys(model.inference_config)[0]; - const remove = getRemoveProcessorForInferenceType(targetField, inferenceType); - const set = getSetProcessorForInferenceType(targetField, inferenceType); - - return { + const pipelineDefinition: MlInferencePipeline = { description: description ?? '', - processors: [ - { - remove: { - field: getMlInferencePrefixedFieldName(targetField), - ignore_missing: true, - }, - }, - ...(remove ? [{ remove }] : []), - { - inference: { - field_map: { - [sourceField]: modelInputField, + processors: [], + version: 1, + }; + + pipelineDefinition.processors = [ + // Add remove and inference processors + ...fieldMappings.flatMap(({ sourceField, targetField }) => { + const remove = getRemoveProcessorForInferenceType(targetField, inferenceType); + const inference = getInferenceProcessor( + sourceField, + targetField, + inferenceConfig, + model, + pipelineName + ); + + return [ + { + remove: { + field: getMlInferencePrefixedFieldName(targetField), + ignore_missing: true, }, - inference_config: inferenceConfig, - model_id: model.model_id, - on_failure: [ - { - append: { - field: '_source._ingest.inference_errors', - value: [ - { - message: `Processor 'inference' in pipeline '${pipelineName}' failed with message '{{ _ingest.on_failure_message }}'`, - pipeline: pipelineName, - timestamp: '{{{ _ingest.timestamp }}}', - }, - ], - }, - }, - ], - target_field: getMlInferencePrefixedFieldName(targetField), }, + ...(remove ? [{ remove }] : []), + { inference }, + ]; + }), + // Add single append processor + { + append: { + field: '_source._ingest.processors', + value: [ + { + model_version: model.version, + pipeline: pipelineName, + processed_timestamp: '{{{ _ingest.timestamp }}}', + types: getMlModelTypesForModelConfig(model), + }, + ], }, + }, + // Add set processors + ...fieldMappings.flatMap(({ targetField }) => { + const set = getSetProcessorForInferenceType(targetField, inferenceType); + + return set ? [{ set }] : []; + }), + ]; + + return pipelineDefinition; +}; + +export const getInferenceProcessor = ( + sourceField: string, + targetField: string, + inferenceConfig: InferencePipelineInferenceConfig | undefined, + model: MlTrainedModelConfig, + pipelineName: string +): IngestInferenceProcessor => { + // If model returned no input field, insert a placeholder + const modelInputField = + model.input?.field_names?.length > 0 ? model.input.field_names[0] : 'MODEL_INPUT_FIELD'; + + return { + field_map: { + [sourceField]: modelInputField, + }, + inference_config: inferenceConfig, + model_id: model.model_id, + on_failure: [ { append: { - field: '_source._ingest.processors', + field: '_source._ingest.inference_errors', value: [ { - model_version: model.version, + message: `Processor 'inference' in pipeline '${pipelineName}' failed with message '{{ _ingest.on_failure_message }}'`, pipeline: pipelineName, - processed_timestamp: '{{{ _ingest.timestamp }}}', - types: getMlModelTypesForModelConfig(model), + timestamp: '{{{ _ingest.timestamp }}}', }, ], }, }, - ...(set ? [{ set }] : []), ], - version: 1, + target_field: getMlInferencePrefixedFieldName(targetField), }; }; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_fields.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_fields.test.tsx new file mode 100644 index 0000000000000..e0146ba1c291e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_fields.test.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 { setMockValues } from '../../../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { ConfigureFields } from './configure_fields'; +import { MultiFieldMapping, SelectedFieldMappings } from './multi_field_selector'; +import { SingleFieldMapping } from './single_field_selector'; + +describe('ConfigureFields', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues({}); + }); + + it('renders multi-field selector components if non-text expansion model is selected', () => { + setMockValues({ + isTextExpansionModelSelected: false, + }); + const wrapper = shallow(); + expect(wrapper.find(SingleFieldMapping)).toHaveLength(1); + expect(wrapper.find(MultiFieldMapping)).toHaveLength(0); + expect(wrapper.find(SelectedFieldMappings)).toHaveLength(0); + }); + it('renders multi-field selector components if text expansion model is selected', () => { + setMockValues({ + isTextExpansionModelSelected: true, + }); + const wrapper = shallow(); + expect(wrapper.find(SingleFieldMapping)).toHaveLength(0); + expect(wrapper.find(MultiFieldMapping)).toHaveLength(1); + expect(wrapper.find(SelectedFieldMappings)).toHaveLength(1); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_fields.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_fields.tsx index 978e5898024b2..c30d01db8d27c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_fields.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_fields.tsx @@ -7,65 +7,19 @@ import React from 'react'; -import { useValues, useActions } from 'kea'; +import { useValues } from 'kea'; -import { - EuiFieldText, - EuiFlexGroup, - EuiFlexItem, - EuiForm, - EuiFormRow, - EuiLink, - EuiPanel, - EuiSelect, - EuiSpacer, - EuiTitle, - EuiText, -} from '@elastic/eui'; +import { EuiForm, EuiSpacer, EuiTitle, EuiText, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; - -import { docLinks } from '../../../../../shared/doc_links'; - -import { IndexViewLogic } from '../../index_view_logic'; +import { InferenceConfiguration } from './inference_config'; import { MLInferenceLogic } from './ml_inference_logic'; -import { TargetFieldHelpText } from './target_field_help_text'; - -const NoSourceFieldsError: React.FC = () => ( - - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.fields.sourceField.error.docLink', - { defaultMessage: 'Learn more about field mapping' } - )} - - ), - }} - /> -); +import { MultiFieldMapping, SelectedFieldMappings } from './multi_field_selector'; +import { SingleFieldMapping } from './single_field_selector'; export const ConfigureFields: React.FC = () => { - const { - addInferencePipelineModal: { configuration }, - formErrors, - supportedMLModels, - sourceFields, - } = useValues(MLInferenceLogic); - const { setInferencePipelineConfiguration } = useActions(MLInferenceLogic); - const { ingestionMethod } = useValues(IndexViewLogic); - - const { destinationField, modelID, pipelineName, sourceField } = configuration; - const emptySourceFields = (sourceFields?.length ?? 0) === 0; - - const inputsDisabled = configuration.existingPipeline !== false; - const selectedModel = supportedMLModels.find((model) => model.model_id === modelID); - + const { isTextExpansionModelSelected } = useValues(MLInferenceLogic); return ( <> @@ -94,89 +48,19 @@ export const ConfigureFields: React.FC = () => { - - - - - } - isInvalid={emptySourceFields} - > - ({ - text: field, - value: field, - })) ?? []), - ]} - onChange={(e) => - setInferencePipelineConfiguration({ - ...configuration, - sourceField: e.target.value, - }) - } - /> - - - - - ) - } - error={formErrors.destinationField} - isInvalid={formErrors.destinationField !== undefined} - fullWidth - > - - setInferencePipelineConfiguration({ - ...configuration, - destinationField: e.target.value, - }) - } - fullWidth - /> - - - - - + + {isTextExpansionModelSelected ? ( + <> + + + + ) : ( + <> + + + + )} + ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_pipeline.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_pipeline.tsx index 67996b6da2f4c..63416c5794165 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_pipeline.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_pipeline.tsx @@ -308,6 +308,7 @@ export const ConfigurePipeline: React.FC = () => { ...configuration, inferenceConfig: undefined, modelID: value, + fieldMappings: undefined, }) } options={modelOptions} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/ml_inference_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/ml_inference_logic.ts index ed0e898618955..996ae0e6e8708 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/ml_inference_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/ml_inference_logic.ts @@ -10,8 +10,10 @@ import { kea, MakeLogicType } from 'kea'; import { IndicesGetMappingIndexMappingRecord } from '@elastic/elasticsearch/lib/api/types'; import { + FieldMapping, formatPipelineName, generateMlInferencePipelineBody, + getMlInferencePrefixedFieldName, getMlModelTypesForModelConfig, parseMlInferenceParametersFromPipeline, } from '../../../../../../../common/ml_inference_pipeline'; @@ -70,10 +72,9 @@ import { } from './types'; import { + getDisabledReason, validateInferencePipelineConfiguration, validateInferencePipelineFields, - EXISTING_PIPELINE_DISABLED_MISSING_SOURCE_FIELD, - EXISTING_PIPELINE_DISABLED_PIPELINE_EXISTS, } from './utils'; export const EMPTY_PIPELINE_CONFIGURATION: InferencePipelineConfiguration = { @@ -97,6 +98,7 @@ export interface MLInferencePipelineOption { } interface MLInferenceProcessorsActions { + addSelectedFieldsToMapping: () => void; attachApiError: Actions< AttachMlInferencePipelineApiLogicArgs, AttachMlInferencePipelineResponse @@ -135,9 +137,11 @@ interface MLInferenceProcessorsActions { FetchMlInferencePipelinesResponse >['apiSuccess']; mlModelsApiError: TrainedModelsApiLogicActions['apiError']; + removeFieldFromMapping: (fieldName: string) => { fieldName: string }; selectExistingPipeline: (pipelineName: string) => { pipelineName: string; }; + selectFields: (fieldNames: string[]) => { fieldNames: string[] }; setAddInferencePipelineStep: (step: AddInferencePipelineSteps) => { step: AddInferencePipelineSteps; }; @@ -151,6 +155,7 @@ export interface AddInferencePipelineModal { configuration: InferencePipelineConfiguration; indexName: string; step: AddInferencePipelineSteps; + selectedSourceFields?: string[] | undefined; } export interface MLInferenceProcessorsValues { @@ -179,10 +184,13 @@ export const MLInferenceLogic = kea< MakeLogicType >({ actions: { + addSelectedFieldsToMapping: true, attachPipeline: true, clearFormErrors: true, createPipeline: true, + removeFieldFromMapping: (fieldName: string) => ({ fieldName }), selectExistingPipeline: (pipelineName: string) => ({ pipelineName }), + selectFields: (fieldNames: string[]) => ({ fieldNames }), setAddInferencePipelineStep: (step: AddInferencePipelineSteps) => ({ step }), setFormErrors: (inputErrors: AddInferencePipelineFormErrors) => ({ inputErrors }), setIndexName: (indexName: string) => ({ indexName }), @@ -310,6 +318,53 @@ export const MLInferenceLogic = kea< step: AddInferencePipelineSteps.Configuration, }, { + addSelectedFieldsToMapping: (modal) => { + const { + configuration: { fieldMappings }, + selectedSourceFields, + } = modal; + + const mergedFieldMappings: FieldMapping[] = [ + ...(fieldMappings || []), + ...(selectedSourceFields || []).map((fieldName) => ({ + sourceField: fieldName, + targetField: getMlInferencePrefixedFieldName(`${fieldName}_expanded`), + })), + ]; + + return { + ...modal, + configuration: { + ...modal.configuration, + fieldMappings: mergedFieldMappings, + }, + selectedSourceFields: [], + }; + }, + removeFieldFromMapping: (modal, { fieldName }) => { + const { + configuration: { fieldMappings }, + } = modal; + + if (!fieldMappings) { + return modal; + } + + return { + ...modal, + configuration: { + ...modal.configuration, + fieldMappings: fieldMappings?.filter(({ sourceField }) => sourceField !== fieldName), + }, + }; + }, + selectFields: (modal, { fieldNames }) => ({ + ...modal, + configuration: { + ...modal.configuration, + }, + selectedSourceFields: fieldNames, + }), setAddInferencePipelineStep: (modal, { step }) => ({ ...modal, step }), setIndexName: (modal, { indexName }) => ({ ...modal, indexName }), setInferencePipelineConfiguration: (modal, { configuration }) => ({ @@ -388,7 +443,7 @@ export const MLInferenceLogic = kea< return generateMlInferencePipelineBody({ model, pipelineName: configuration.pipelineName, - fieldMappings: [ + fieldMappings: configuration.fieldMappings || [ { sourceField: configuration.sourceField, targetField: @@ -461,21 +516,19 @@ export const MLInferenceLogic = kea< source_field: sourceField, } = pipelineParams; - let disabled: boolean = false; - let disabledReason: string | undefined; - if (!(sourceFields?.includes(sourceField) ?? false)) { - disabled = true; - disabledReason = EXISTING_PIPELINE_DISABLED_MISSING_SOURCE_FIELD; - } else if (indexProcessorNames.includes(pipelineName)) { - disabled = true; - disabledReason = EXISTING_PIPELINE_DISABLED_PIPELINE_EXISTS; - } const mlModel = supportedMLModels.find((model) => model.model_id === modelId); const modelType = mlModel ? getMLType(getMlModelTypesForModelConfig(mlModel)) : ''; + const disabledReason = getDisabledReason( + sourceFields, + sourceField, + indexProcessorNames, + pipelineName, + modelType + ); return { destinationField: destinationField ?? '', - disabled, + disabled: disabledReason !== undefined, disabledReason, modelId, modelType, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/multi_field_selector.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/multi_field_selector.test.tsx new file mode 100644 index 0000000000000..b32b23ff89733 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/multi_field_selector.test.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { setMockValues } from '../../../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiBasicTable, EuiButton, EuiComboBox } from '@elastic/eui'; + +import { MultiFieldMapping, SelectedFieldMappings } from './multi_field_selector'; + +const DEFAULT_VALUES = { + addInferencePipelineModal: { + configuration: {}, + }, + sourceFields: ['my-source-field1', 'my-source-field2', 'my-source-field3'], +}; + +describe('MultiFieldMapping', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues({}); + }); + it('renders multi field selector with options', () => { + setMockValues(DEFAULT_VALUES); + const wrapper = shallow(); + + expect(wrapper.find(EuiComboBox)).toHaveLength(1); + const comboBox = wrapper.find(EuiComboBox); + expect(comboBox.prop('options')).toEqual([ + { + label: 'my-source-field1', + }, + { + label: 'my-source-field2', + }, + { + label: 'my-source-field3', + }, + ]); + }); + it('renders multi field selector with options excluding mapped and selected fields', () => { + setMockValues({ + ...DEFAULT_VALUES, + addInferencePipelineModal: { + configuration: { + fieldMappings: [ + { + sourceField: 'my-source-field2', + targetField: 'my-target-field2', + }, + ], + }, + selectedSourceFields: ['my-source-field1'], + }, + }); + const wrapper = shallow(); + + expect(wrapper.find(EuiComboBox)).toHaveLength(1); + const comboBox = wrapper.find(EuiComboBox); + expect(comboBox.prop('options')).toEqual([ + { + label: 'my-source-field3', + }, + ]); + }); + it('disables add mapping button if no fields are selected', () => { + setMockValues(DEFAULT_VALUES); + const wrapper = shallow(); + + expect(wrapper.find(EuiButton)).toHaveLength(1); + const button = wrapper.find(EuiButton); + expect(button.prop('disabled')).toBe(true); + }); + it('enables add mapping button if some fields are selected', () => { + setMockValues({ + ...DEFAULT_VALUES, + addInferencePipelineModal: { + ...DEFAULT_VALUES.addInferencePipelineModal, + selectedSourceFields: ['my-source-field1'], + }, + }); + const wrapper = shallow(); + + expect(wrapper.find(EuiButton)).toHaveLength(1); + const button = wrapper.find(EuiButton); + expect(button.prop('disabled')).toBe(false); + }); +}); + +describe('SelectedFieldMappings', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues({}); + }); + it('renders field mapping list', () => { + const mockValues = { + ...DEFAULT_VALUES, + addInferencePipelineModal: { + configuration: { + fieldMappings: [ + { + sourceField: 'my-source-field1', + targetField: 'my-target-field1', + }, + { + sourceField: 'my-source-field2', + targetField: 'my-target-field2', + }, + ], + }, + }, + }; + setMockValues(mockValues); + const wrapper = shallow(); + + expect(wrapper.find(EuiBasicTable)).toHaveLength(1); + const table = wrapper.find(EuiBasicTable); + expect(table.prop('items')).toEqual( + mockValues.addInferencePipelineModal.configuration.fieldMappings + ); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/multi_field_selector.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/multi_field_selector.tsx new file mode 100644 index 0000000000000..fbbab9e8971a8 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/multi_field_selector.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { useValues, useActions } from 'kea'; + +import { + EuiBasicTable, + EuiBasicTableColumn, + EuiButton, + EuiComboBox, + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiIcon, +} from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + +import { FieldMapping } from '../../../../../../../common/ml_inference_pipeline'; + +import { IndexViewLogic } from '../../index_view_logic'; + +import { MLInferenceLogic } from './ml_inference_logic'; + +type FieldNames = Array<{ label: string }>; + +export const MultiFieldMapping: React.FC = () => { + const { + addInferencePipelineModal: { configuration, selectedSourceFields = [] }, + sourceFields, + } = useValues(MLInferenceLogic); + const { ingestionMethod } = useValues(IndexViewLogic); + const { addSelectedFieldsToMapping, selectFields } = useActions(MLInferenceLogic); + + const mappedSourceFields = + configuration.fieldMappings?.map(({ sourceField }) => sourceField) ?? []; + + // Remove fields that have already been selected or mapped from selectable field options + const fieldOptions = (sourceFields || []) + .filter((fieldName) => ![...selectedSourceFields, ...mappedSourceFields].includes(fieldName)) + .map((fieldName) => ({ label: fieldName })); + + const selectedFields = selectedSourceFields.map((fieldName) => ({ + label: fieldName, + })); + + const onChangeSelectedFields = (selectedFieldNames: FieldNames) => { + selectFields(selectedFieldNames.map(({ label }) => label)); + }; + + const onCreateField = (fieldName: string) => { + const normalizedFieldName = fieldName.trim(); + if (!normalizedFieldName) return; + + selectedFields.push({ label: normalizedFieldName }); + selectFields([...selectedSourceFields, fieldName]); + }; + + return ( + <> + + + + + + + + + + + + + + + + + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.fields.addMapping', + { + defaultMessage: 'Add', + } + )} + + + + + ); +}; + +export const SelectedFieldMappings: React.FC = () => { + const { removeFieldFromMapping } = useActions(MLInferenceLogic); + const { + addInferencePipelineModal: { configuration }, + } = useValues(MLInferenceLogic); + + const columns: Array> = [ + { + 'data-test-subj': 'sourceFieldCell', + field: 'sourceField', + name: i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.fields.fieldMappings.sourceFieldHeader', + { + defaultMessage: 'Source fields', + } + ), + }, + { + align: 'left', + name: '', + render: () => , + width: '60px', + }, + { + field: 'targetField', + name: i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.fields.fieldMappings.targetFieldHeader', + { + defaultMessage: 'Target fields', + } + ), + }, + { + actions: [ + { + color: 'danger', + description: i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.fields.actions.deleteMapping', + { + defaultMessage: 'Delete this mapping', + } + ), + icon: 'trash', + isPrimary: true, + name: (fieldMapping) => + i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.fields.actions.deleteMapping.caption', + { + defaultMessage: `Delete mapping '{sourceField}' - '{targetField}'`, + values: { + sourceField: fieldMapping.sourceField, + targetField: fieldMapping.targetField, + }, + } + ), + onClick: (fieldMapping) => removeFieldFromMapping(fieldMapping.sourceField), + type: 'icon', + }, + ], + name: i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.fields.actions', + { + defaultMessage: 'Actions', + } + ), + width: '10%', + }, + ]; + + return ( + <> + + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/pipeline_select_option.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/pipeline_select_option.tsx index 0bb2dfbbfbfe5..cc112f30d91e8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/pipeline_select_option.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/pipeline_select_option.tsx @@ -7,9 +7,11 @@ import React from 'react'; -import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiTextColor, EuiTitle } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiTextColor, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { MLModelTypeBadge } from '../ml_model_type_badge'; + import { MLInferencePipelineOption } from './ml_inference_logic'; import { EXISTING_PIPELINE_DISABLED_MISSING_SOURCE_FIELD, MODEL_REDACTED_VALUE } from './utils'; @@ -51,9 +53,7 @@ export const PipelineSelectOption: React.FC = ({ pipe {pipeline.modelType.length > 0 && ( - - {pipeline.modelType} - + )} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/single_field_selector.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/single_field_selector.test.tsx new file mode 100644 index 0000000000000..ce4a9629c4542 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/single_field_selector.test.tsx @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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 { setMockValues } from '../../../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiFieldText, EuiSelect } from '@elastic/eui'; + +import { SingleFieldMapping } from './single_field_selector'; + +const DEFAULT_VALUES = { + addInferencePipelineModal: { + configuration: { + sourceField: 'my-source-field', + destinationField: 'my-target-field', + }, + }, + formErrors: {}, + sourceFields: ['my-source-field1', 'my-source-field2', 'my-source-field3'], + supportedMLModels: [], +}; + +describe('SingleFieldMapping', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues({}); + }); + it('renders source field selector and target field text field', () => { + setMockValues(DEFAULT_VALUES); + const wrapper = shallow(); + + expect(wrapper.find(EuiSelect)).toHaveLength(1); + const select = wrapper.find(EuiSelect); + expect(select.prop('options')).toEqual([ + { + disabled: true, + text: 'Select a schema field', + value: '', + }, + { + text: 'my-source-field1', + value: 'my-source-field1', + }, + { + text: 'my-source-field2', + value: 'my-source-field2', + }, + { + text: 'my-source-field3', + value: 'my-source-field3', + }, + ]); + expect(select.prop('value')).toEqual('my-source-field'); + + expect(wrapper.find(EuiFieldText)).toHaveLength(1); + const textField = wrapper.find(EuiFieldText); + expect(textField.prop('value')).toEqual('my-target-field'); + }); + it('disables inputs when selecting an existing pipeline', () => { + setMockValues({ + ...DEFAULT_VALUES, + addInferencePipelineModal: { + ...DEFAULT_VALUES.addInferencePipelineModal, + configuration: { + ...DEFAULT_VALUES.addInferencePipelineModal.configuration, + existingPipeline: true, + }, + }, + }); + const wrapper = shallow(); + + expect(wrapper.find(EuiSelect)).toHaveLength(1); + const select = wrapper.find(EuiSelect); + expect(select.prop('disabled')).toBe(true); + + expect(wrapper.find(EuiFieldText)).toHaveLength(1); + const textField = wrapper.find(EuiFieldText); + expect(textField.prop('disabled')).toBe(true); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/single_field_selector.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/single_field_selector.tsx new file mode 100644 index 0000000000000..9cc4e77cbba5d --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/single_field_selector.tsx @@ -0,0 +1,145 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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, useActions } from 'kea'; + +import { + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiLink, + EuiSelect, +} from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; + +import { docLinks } from '../../../../../shared/doc_links'; + +import { IndexViewLogic } from '../../index_view_logic'; + +import { MLInferenceLogic } from './ml_inference_logic'; +import { TargetFieldHelpText } from './target_field_help_text'; + +const NoSourceFieldsError: React.FC = () => ( + + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.fields.sourceField.error.docLink', + { defaultMessage: 'Learn more about field mapping' } + )} + + ), + }} + /> +); + +export const SingleFieldMapping: React.FC = () => { + const { + addInferencePipelineModal: { configuration }, + formErrors, + supportedMLModels, + sourceFields, + } = useValues(MLInferenceLogic); + const { setInferencePipelineConfiguration } = useActions(MLInferenceLogic); + const { ingestionMethod } = useValues(IndexViewLogic); + + const { destinationField, modelID, pipelineName, sourceField } = configuration; + const isEmptySourceFields = (sourceFields?.length ?? 0) === 0; + const areInputsDisabled = configuration.existingPipeline !== false; + const selectedModel = supportedMLModels.find((model) => model.model_id === modelID); + return ( + <> + + + } + isInvalid={isEmptySourceFields} + > + ({ + text: field, + value: field, + })) ?? []), + ]} + onChange={(e) => + setInferencePipelineConfiguration({ + ...configuration, + sourceField: e.target.value, + }) + } + /> + + + + + ) + } + error={formErrors.destinationField} + isInvalid={formErrors.destinationField !== undefined} + fullWidth + > + + setInferencePipelineConfiguration({ + ...configuration, + destinationField: e.target.value, + }) + } + fullWidth + /> + + + + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/test_pipeline.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/test_pipeline.tsx index effbe28a86a00..2e7fbd51e9147 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/test_pipeline.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/test_pipeline.tsx @@ -62,7 +62,6 @@ export const TestPipeline: React.FC = () => { )} - diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/types.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/types.ts index 3b155f8b32310..ec1246ab8b464 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/types.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/types.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { FieldMapping } from '../../../../../../../common/ml_inference_pipeline'; + import { InferencePipelineInferenceConfig } from '../../../../../../../common/types/pipelines'; export interface InferencePipelineConfiguration { @@ -14,6 +16,7 @@ export interface InferencePipelineConfiguration { modelID: string; pipelineName: string; sourceField: string; + fieldMappings?: FieldMapping[]; } export interface AddInferencePipelineFormErrors { diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/utils.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/utils.ts index 31a11c40770ae..7418ae14108e9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/utils.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/utils.ts @@ -7,6 +7,8 @@ import { i18n } from '@kbn/i18n'; +import { SUPPORTED_PYTORCH_TASKS } from '@kbn/ml-trained-models-utils'; + import { AddInferencePipelineFormErrors, InferencePipelineConfiguration } from './types'; const VALID_PIPELINE_NAME_REGEX = /^[\w\-]+$/; @@ -53,6 +55,12 @@ export const validateInferencePipelineFields = ( config: InferencePipelineConfiguration ): AddInferencePipelineFormErrors => { const errors: AddInferencePipelineFormErrors = {}; + + // If there are field mappings, we don't need to validate the single source field + if (config.fieldMappings && Object.keys(config.fieldMappings).length > 0) { + return errors; + } + if (config.sourceField.trim().length === 0) { errors.sourceField = FIELD_REQUIRED_ERROR; } @@ -75,6 +83,32 @@ export const EXISTING_PIPELINE_DISABLED_PIPELINE_EXISTS = i18n.translate( } ); +export const EXISTING_PIPELINE_DISABLED_TEXT_EXPANSION = i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.disabledElserNotSupportedDescription', + { + defaultMessage: + 'This pipeline cannot be selected because attaching an ELSER pipeline is not supported yet.', + } +); + +export const getDisabledReason = ( + sourceFields: string[] | undefined, + sourceField: string, + indexProcessorNames: string[], + pipelineName: string, + modelType: string +): string | undefined => { + if (!(sourceFields?.includes(sourceField) ?? false)) { + return EXISTING_PIPELINE_DISABLED_MISSING_SOURCE_FIELD; + } else if (indexProcessorNames.includes(pipelineName)) { + return EXISTING_PIPELINE_DISABLED_PIPELINE_EXISTS; + } else if (modelType === SUPPORTED_PYTORCH_TASKS.TEXT_EXPANSION) { + return EXISTING_PIPELINE_DISABLED_TEXT_EXPANSION; + } + + return undefined; +}; + export const MODEL_SELECT_PLACEHOLDER = i18n.translate( 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.model.placeholder', { defaultMessage: 'Select a model' } From 6294b1b4b84f4fe27434eb06b803cce40b6d236b Mon Sep 17 00:00:00 2001 From: Bhavya RM Date: Tue, 11 Apr 2023 16:05:44 -0400 Subject: [PATCH 13/23] Adding additional verification for checking that 6.8.x dashboard (upgraded to 7.17.x) rendering correctly (#154384) --- .../import_saved_objects_between_versions.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/saved_objects_management/import_saved_objects_between_versions.ts b/x-pack/test/functional/apps/saved_objects_management/import_saved_objects_between_versions.ts index f4b6ad3fe20c8..7761af2684cbb 100644 --- a/x-pack/test/functional/apps/saved_objects_management/import_saved_objects_between_versions.ts +++ b/x-pack/test/functional/apps/saved_objects_management/import_saved_objects_between_versions.ts @@ -47,7 +47,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.savedObjects.cleanStandardList(); }); - it('should be able to import 7.13 saved objects into 8.0.0 and verfiy the rendering of two dashboards', async function () { + it('should be able to import 7.13 saved objects into 8.0.0 and verfiy the rendering of three dashboards', async function () { const initialObjectCount = await PageObjects.savedObjects.getExportCount(); await PageObjects.savedObjects.importFile( path.join(__dirname, 'exports', '_7.13_import_saved_objects.ndjson') @@ -76,6 +76,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await renderService.waitForRender(2); // There should be 0 error embeddables on the dashboard await PageObjects.dashboard.verifyNoRenderErrors(); + + // logstash_dashboardwithfilters + await PageObjects.dashboard.loadSavedDashboard('logstash_dashboardwithfilters'); + await PageObjects.dashboard.expectOnDashboard('logstash_dashboardwithfilters'); + + // count of panels rendered completely + await renderService.waitForRender(20); + // There should be 0 error embeddables on the dashboard + await PageObjects.dashboard.verifyNoRenderErrors(); }); it('should be able to import alerts and actions saved objects from 7.14 into 8.0.0', async function () { From 67af39ab0c6987d215a3073f0df92641fdcdd8c6 Mon Sep 17 00:00:00 2001 From: Angela Chuang <6295984+angorayc@users.noreply.github.com> Date: Tue, 11 Apr 2023 21:15:37 +0100 Subject: [PATCH 14/23] [SecuritySolution] Setup dashboard view page (#153040) ## Summary https://github.com/elastic/kibana/issues/152955 Demo link: https://kibana-pr-153040.kb.us-west2.gcp.elastic-cloud.com:9243/app/security/dashboards/6294c960-ce35-11ed-b8ca-51636b04063c?sourcerer=(default:(id:security-solution-default,selectedPatterns:!(%27auditbeat-*%27,%27logs-*%27))) https://p.elstc.co/paste/pOFVo-fV#Zgp3hnsnijsDHbki4y9Cy5F+apet-hYEcedpDzsc+f7 This create a single dashboard view under Security Solution: - Add dashboard view path: `/app/security/dashboards/:dashboardId` - Move the dashboards landing page to this new sub-plugin. - Check users' read permission to render a dashboard. - Render a dashboard with the given saved object id. - Show the dashboard name in the breadcrumbs. Dashboard not found: Screenshot 2023-03-23 at 13 44 01 Dashboard rendered: Screenshot 2023-03-23 at 13 44 28 Interact with filters and query: https://user-images.githubusercontent.com/6295984/227477735-dc53bb85-31fb-4043-8355-22866296ebf9.mov Interact with `Open in Lens` and `Investigate in timeline` https://user-images.githubusercontent.com/6295984/228217900-5055a5d1-46f2-4d2f-98a8-289eb0f1939a.mov **Steps to verify**: 1. Create a dashboard from `/app/dashboards#/list`, save it and copy the dashboard saved object id from url. 2. Visit `/app/security/dashboards/:dashboardId` ### Checklist Delete any items that are not applicable to this PR. - [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: Stratoula Kalafateli Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../public/search_bar/search_bar.tsx | 15 ++ .../security_solution/common/constants.ts | 2 +- .../public/app/deep_links/index.ts | 2 +- .../dashboards/dashboard_renderer.test.tsx | 58 ++++++++ .../dashboards/dashboard_renderer.tsx | 91 ++++++++++++ .../navigation/breadcrumbs/index.ts | 3 + .../components/page_route/pageroute.test.tsx | 33 ----- .../components/page_route/pageroute.tsx | 16 --- .../common/components/search_bar/index.tsx | 19 ++- .../use_security_dashboards_table.test.tsx | 20 +++ .../use_security_dashboards_table.tsx | 13 +- .../public/common/links/app_links.ts | 3 +- .../public/common/utils/route/types.ts | 2 + .../components/edit_dashboard_button.test.tsx | 41 ++++++ .../components/edit_dashboard_button.tsx | 59 ++++++++ .../components/status_prompt.test.tsx | 27 ++++ .../dashboards/components/status_prompt.tsx | 25 ++++ .../hooks/use_dashboard_app_link.test.tsx | 133 ++++++++++++++++++ .../hooks/use_dashboard_app_link.tsx | 71 ++++++++++ .../use_dashboard_view_prompt_state.test.tsx | 57 ++++++++ .../hooks/use_dashboard_view_prompt_state.tsx | 35 +++++ .../index.tsx => dashboards/index.ts} | 12 +- .../public/dashboards/jest.config.js | 19 +++ .../public/dashboards/links.ts | 40 ++++++ .../public/dashboards/pages/details/index.tsx | 106 ++++++++++++++ .../dashboards/pages/details/translations.ts | 35 +++++ .../public/dashboards/pages/index.tsx | 28 ++++ .../pages/landing_page/index.test.tsx} | 28 ++-- .../pages/landing_page/index.tsx} | 44 +++--- .../pages/landing_page/translations.ts | 28 ++++ .../public/dashboards/pages/translations.ts | 15 ++ .../public/dashboards/pages/utils.ts | 26 ++++ .../public/dashboards/routes.tsx | 28 ++++ .../public/landing_pages/links.ts | 40 +----- .../landing_pages/pages/translations.ts | 28 ---- .../public/landing_pages/routes.tsx | 15 +- .../public/lazy_sub_plugins.tsx | 2 + .../security_solution/public/plugin.tsx | 14 +- .../plugins/security_solution/public/types.ts | 32 +++-- .../translations/translations/fr-FR.json | 4 - .../translations/translations/ja-JP.json | 4 - .../translations/translations/zh-CN.json | 4 - 42 files changed, 1070 insertions(+), 207 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/common/components/dashboards/dashboard_renderer.test.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/dashboards/dashboard_renderer.tsx delete mode 100644 x-pack/plugins/security_solution/public/common/components/page_route/pageroute.test.tsx delete mode 100644 x-pack/plugins/security_solution/public/common/components/page_route/pageroute.tsx create mode 100644 x-pack/plugins/security_solution/public/dashboards/components/edit_dashboard_button.test.tsx create mode 100644 x-pack/plugins/security_solution/public/dashboards/components/edit_dashboard_button.tsx create mode 100644 x-pack/plugins/security_solution/public/dashboards/components/status_prompt.test.tsx create mode 100644 x-pack/plugins/security_solution/public/dashboards/components/status_prompt.tsx create mode 100644 x-pack/plugins/security_solution/public/dashboards/hooks/use_dashboard_app_link.test.tsx create mode 100644 x-pack/plugins/security_solution/public/dashboards/hooks/use_dashboard_app_link.tsx create mode 100644 x-pack/plugins/security_solution/public/dashboards/hooks/use_dashboard_view_prompt_state.test.tsx create mode 100644 x-pack/plugins/security_solution/public/dashboards/hooks/use_dashboard_view_prompt_state.tsx rename x-pack/plugins/security_solution/public/{common/components/page_route/index.tsx => dashboards/index.ts} (54%) create mode 100644 x-pack/plugins/security_solution/public/dashboards/jest.config.js create mode 100644 x-pack/plugins/security_solution/public/dashboards/links.ts create mode 100644 x-pack/plugins/security_solution/public/dashboards/pages/details/index.tsx create mode 100644 x-pack/plugins/security_solution/public/dashboards/pages/details/translations.ts create mode 100644 x-pack/plugins/security_solution/public/dashboards/pages/index.tsx rename x-pack/plugins/security_solution/public/{landing_pages/pages/dashboards.test.tsx => dashboards/pages/landing_page/index.test.tsx} (85%) rename x-pack/plugins/security_solution/public/{landing_pages/pages/dashboards.tsx => dashboards/pages/landing_page/index.tsx} (63%) create mode 100644 x-pack/plugins/security_solution/public/dashboards/pages/landing_page/translations.ts create mode 100644 x-pack/plugins/security_solution/public/dashboards/pages/translations.ts create mode 100644 x-pack/plugins/security_solution/public/dashboards/pages/utils.ts create mode 100644 x-pack/plugins/security_solution/public/dashboards/routes.tsx diff --git a/src/plugins/unified_search/public/search_bar/search_bar.tsx b/src/plugins/unified_search/public/search_bar/search_bar.tsx index 4d96e1d605ab3..0a83a45de1d03 100644 --- a/src/plugins/unified_search/public/search_bar/search_bar.tsx +++ b/src/plugins/unified_search/public/search_bar/search_bar.tsx @@ -75,6 +75,8 @@ export interface SearchBarOwnProps { onSaved?: (savedQuery: SavedQuery) => void; // User has modified the saved query, your app should persist the update onSavedQueryUpdated?: (savedQuery: SavedQuery) => void; + // Execute whenever time range is updated. + onTimeRangeChange?: (payload: { dateRange: TimeRange }) => void; // User has cleared the active query, your app should clear the entire query bar onClearSavedQuery?: () => void; @@ -187,6 +189,19 @@ class SearchBarUI extends C if (nextDateRange) { nextState.dateRangeFrom = nextDateRange.dateRangeFrom; nextState.dateRangeTo = nextDateRange.dateRangeTo; + + /** + * Some applications do not rely on the _g url parameter to update the time. The onTimeRangeChange + * callback can be used in these cases to notify the consumer for the time change. + */ + if (nextDateRange.dateRangeFrom && nextDateRange.dateRangeTo) { + nextProps?.onTimeRangeChange?.({ + dateRange: { + from: nextDateRange.dateRangeFrom, + to: nextDateRange.dateRangeTo, + }, + }); + } } return nextState; } diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index 8794e81e4a441..1ae377fd65b96 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -97,7 +97,7 @@ export enum SecurityPageName { * All cloud defend page names must match `CloudDefendPageId` in x-pack/plugins/cloud_defend/public/common/navigation/types.ts */ cloudDefendPolicies = 'cloud_defend-policies', - dashboardsLanding = 'dashboards', + dashboards = 'dashboards', dataQuality = 'data_quality', detections = 'detections', detectionAndResponse = 'detection_response', diff --git a/x-pack/plugins/security_solution/public/app/deep_links/index.ts b/x-pack/plugins/security_solution/public/app/deep_links/index.ts index 87d43742a9433..7ea8a9f51f406 100644 --- a/x-pack/plugins/security_solution/public/app/deep_links/index.ts +++ b/x-pack/plugins/security_solution/public/app/deep_links/index.ts @@ -132,7 +132,7 @@ export const securitySolutionsDeepLinks: SecuritySolutionDeepLink[] = [ ], }, { - id: SecurityPageName.dashboardsLanding, + id: SecurityPageName.dashboards, title: DASHBOARDS, path: OVERVIEW_PATH, navLinkStatus: AppNavLinkStatus.visible, diff --git a/x-pack/plugins/security_solution/public/common/components/dashboards/dashboard_renderer.test.tsx b/x-pack/plugins/security_solution/public/common/components/dashboards/dashboard_renderer.test.tsx new file mode 100644 index 0000000000000..78c57d598c3dc --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/dashboards/dashboard_renderer.test.tsx @@ -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 { render } from '@testing-library/react'; +import React from 'react'; +import { TestProviders } from '../../mock'; +import { DashboardRenderer } from './dashboard_renderer'; + +jest.mock('@kbn/dashboard-plugin/public', () => { + const actual = jest.requireActual('@kbn/dashboard-plugin/public'); + return { + ...actual, + LazyDashboardContainerRenderer: jest + .fn() + .mockImplementation(() =>
), + }; +}); + +jest.mock('react-router-dom', () => { + const actual = jest.requireActual('react-router-dom'); + return { + ...actual, + useParams: jest.fn().mockReturnValue({ + detailName: '2d50f100-be6f-11ed-964a-ffa67304840e', + }), + }; +}); + +describe('DashboardRenderer', () => { + const props = { + canReadDashboard: true, + id: 'dashboard-savedObjectId', + savedObjectId: 'savedObjectId', + timeRange: { + from: '2023-03-10T00:00:00.000Z', + to: '2023-03-10T23:59:59.999Z', + }, + }; + + it('renders', () => { + const { queryByTestId } = render(, { wrapper: TestProviders }); + expect(queryByTestId(`dashboardRenderer`)).toBeInTheDocument(); + }); + + it('does not render when No Read Permission', () => { + const testProps = { + ...props, + canReadDashboard: false, + }; + const { queryByTestId } = render(, { + wrapper: TestProviders, + }); + expect(queryByTestId(`dashboardRenderer`)).not.toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/dashboards/dashboard_renderer.tsx b/x-pack/plugins/security_solution/public/common/components/dashboards/dashboard_renderer.tsx new file mode 100644 index 0000000000000..e8c521e9fd8c4 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/dashboards/dashboard_renderer.tsx @@ -0,0 +1,91 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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, useEffect, useState } from 'react'; +import type { DashboardContainer } from '@kbn/dashboard-plugin/public'; +import { LazyDashboardContainerRenderer } from '@kbn/dashboard-plugin/public'; +import { ViewMode } from '@kbn/embeddable-plugin/public'; +import type { Filter, Query } from '@kbn/es-query'; + +import { useDispatch } from 'react-redux'; +import { InputsModelId } from '../../store/inputs/constants'; +import { inputsActions } from '../../store/inputs'; + +const DashboardRendererComponent = ({ + canReadDashboard, + filters, + id, + inputId = InputsModelId.global, + onDashboardContainerLoaded, + query, + savedObjectId, + timeRange, +}: { + canReadDashboard: boolean; + filters?: Filter[]; + id: string; + inputId?: InputsModelId.global | InputsModelId.timeline; + onDashboardContainerLoaded?: (dashboardContainer: DashboardContainer) => void; + query?: Query; + savedObjectId: string | undefined; + timeRange: { + from: string; + fromStr?: string | undefined; + to: string; + toStr?: string | undefined; + }; +}) => { + const dispatch = useDispatch(); + const [dashboardContainer, setDashboardContainer] = useState(); + + const getCreationOptions = useCallback( + () => + Promise.resolve({ + overrideInput: { timeRange, viewMode: ViewMode.VIEW, query, filters }, + }), + [filters, query, timeRange] + ); + + const refetchByForceRefresh = useCallback(() => { + dashboardContainer?.forceRefresh(); + }, [dashboardContainer]); + + useEffect(() => { + dispatch( + inputsActions.setQuery({ + inputId, + id, + refetch: refetchByForceRefresh, + loading: false, + inspect: null, + }) + ); + return () => { + dispatch(inputsActions.deleteOneQuery({ inputId, id })); + }; + }, [dispatch, id, inputId, refetchByForceRefresh]); + + useEffect(() => { + dashboardContainer?.updateInput({ timeRange, query, filters }); + }, [dashboardContainer, filters, query, timeRange]); + + const handleDashboardLoaded = useCallback( + (container: DashboardContainer) => { + setDashboardContainer(container); + onDashboardContainerLoaded?.(container); + }, + [onDashboardContainerLoaded] + ); + return savedObjectId && canReadDashboard ? ( + + ) : null; +}; +DashboardRendererComponent.displayName = 'DashboardRendererComponent'; +export const DashboardRenderer = React.memo(DashboardRendererComponent); diff --git a/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.ts b/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.ts index 6dd4a0e94530d..2b0258d74a45f 100644 --- a/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.ts +++ b/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.ts @@ -19,6 +19,7 @@ import { getTrailingBreadcrumbs as getCSPBreadcrumbs } from '../../../../cloud_s import { getTrailingBreadcrumbs as getUsersBreadcrumbs } from '../../../../explore/users/pages/details/utils'; import { getTrailingBreadcrumbs as getKubernetesBreadcrumbs } from '../../../../kubernetes/pages/utils/breadcrumbs'; import { getTrailingBreadcrumbs as getAlertDetailBreadcrumbs } from '../../../../detections/pages/alert_details/utils/breadcrumbs'; +import { getTrailingBreadcrumbs as getDashboardBreadcrumbs } from '../../../../dashboards/pages/utils'; import { SecurityPageName } from '../../../../app/types'; import type { RouteSpyState } from '../../../utils/route/types'; import { timelineActions } from '../../../../timelines/store/timeline'; @@ -134,6 +135,8 @@ const getTrailingBreadcrumbsForRoutes = ( return getAlertDetailBreadcrumbs(spyState, getSecuritySolutionUrl); case SecurityPageName.cloudSecurityPostureBenchmarks: return getCSPBreadcrumbs(spyState, getSecuritySolutionUrl); + case SecurityPageName.dashboards: + return getDashboardBreadcrumbs(spyState); } return []; diff --git a/x-pack/plugins/security_solution/public/common/components/page_route/pageroute.test.tsx b/x-pack/plugins/security_solution/public/common/components/page_route/pageroute.test.tsx deleted file mode 100644 index 3621907ea9ef3..0000000000000 --- a/x-pack/plugins/security_solution/public/common/components/page_route/pageroute.test.tsx +++ /dev/null @@ -1,33 +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 { PageRoute } from './pageroute'; -import type { ReactWrapper } from 'enzyme'; -import { mount } from 'enzyme'; - -describe('pageroute', () => { - const documentTitle = 'Kibana'; - - const fakeComponent = () =>
{'fake component'}
; - let wrapper: ReactWrapper; - beforeAll(() => { - wrapper = mount(); - }); - - afterAll(() => { - document.title = documentTitle; - }); - - test('renders target component correctly', () => { - expect(wrapper.find(fakeComponent)).toBeTruthy(); - }); - - test('updates page title correctly', () => { - expect(document.title).toEqual('test - Kibana'); - }); -}); diff --git a/x-pack/plugins/security_solution/public/common/components/page_route/pageroute.tsx b/x-pack/plugins/security_solution/public/common/components/page_route/pageroute.tsx deleted file mode 100644 index 1270b815d067d..0000000000000 --- a/x-pack/plugins/security_solution/public/common/components/page_route/pageroute.tsx +++ /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 React, { useEffect } from 'react'; - -export const PageRoute = (props: { title: string; component: React.ReactType }) => { - const { title, ...rest } = props; - useEffect(() => { - document.title = `${title} - Kibana`; - }, [title]); - return ; -}; diff --git a/x-pack/plugins/security_solution/public/common/components/search_bar/index.tsx b/x-pack/plugins/security_solution/public/common/components/search_bar/index.tsx index dfbe1e5a39873..55571cc9dfa69 100644 --- a/x-pack/plugins/security_solution/public/common/components/search_bar/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/search_bar/index.tsx @@ -295,7 +295,23 @@ export const SearchBarComponent = memo( }, []); const indexPatterns = useMemo(() => [indexPattern], [indexPattern]); - + const onTimeRangeChange = useCallback( + ({ query, dateRange }) => { + const isQuickSelection = dateRange.from.includes('now') || dateRange.to.includes('now'); + updateSearch({ + end: dateRange.to, + filterManager, + id, + isInvalid: false, + isQuickSelection, + query, + setTablesActivePageToZero, + start: dateRange.from, + updateTime: true, + }); + }, + [filterManager, id, setTablesActivePageToZero, updateSearch] + ); return (
( onQuerySubmit={onQuerySubmit} onRefresh={onRefresh} onSaved={onSaved} + onTimeRangeChange={onTimeRangeChange} onSavedQueryUpdated={onSavedQueryUpdated} savedQuery={savedQuery} showFilterBar={!hideFilterBar} diff --git a/x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.test.tsx b/x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.test.tsx index 143a1335d4de8..c68ca947b89ce 100644 --- a/x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.test.tsx +++ b/x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.test.tsx @@ -17,9 +17,13 @@ import { useSecurityDashboardsTableItems, } from './use_security_dashboards_table'; import * as telemetry from '../../lib/telemetry'; +import { SecurityPageName } from '../../../../common/constants'; +import * as linkTo from '../../components/link_to'; import type { DashboardTableItem } from './types'; jest.mock('../../lib/kibana'); + +const spyUseGetSecuritySolutionUrl = jest.spyOn(linkTo, 'useGetSecuritySolutionUrl'); const spyTrack = jest.spyOn(telemetry, 'track'); const TAG_ID = 'securityTagId'; @@ -202,4 +206,20 @@ describe('Security Dashboards Table hooks', () => { telemetry.TELEMETRY_EVENT.DASHBOARD ); }); + + it('should land on SecuritySolution dashboard view page when dashboard title clicked', async () => { + const mockGetSecuritySolutionUrl = jest.fn(); + spyUseGetSecuritySolutionUrl.mockImplementation(() => mockGetSecuritySolutionUrl); + const { result: itemsResult } = await renderUseSecurityDashboardsTableItems(); + const { result: columnsResult } = renderUseDashboardsTableColumns(); + + render(, { + wrapper: TestProviders, + }); + + expect(mockGetSecuritySolutionUrl).toHaveBeenCalledWith({ + deepLinkId: SecurityPageName.dashboards, + path: 'dashboardId1', + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx b/x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx index 9380ce31ea49c..21081a66b7df5 100644 --- a/x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx +++ b/x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx @@ -14,6 +14,9 @@ import { useKibana, useNavigateTo } from '../../lib/kibana'; import * as i18n from './translations'; import { useFetch, REQUEST_NAMES } from '../../hooks/use_fetch'; import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../lib/telemetry'; +import { SecurityPageName } from '../../../../common/constants'; +import { useGetSecuritySolutionUrl } from '../../components/link_to'; + import type { DashboardTableItem } from './types'; const EMPTY_DESCRIPTION = '-' as const; @@ -49,8 +52,9 @@ export const useSecurityDashboardsTableItems = () => { export const useSecurityDashboardsTableColumns = (): Array< EuiBasicTableColumn > => { - const { savedObjectsTagging, dashboard } = useKibana().services; + const { savedObjectsTagging } = useKibana().services; const { navigateTo } = useNavigateTo(); + const getSecuritySolutionUrl = useGetSecuritySolutionUrl(); const getNavigationHandler = useCallback( (href: string): MouseEventHandler => @@ -69,7 +73,10 @@ export const useSecurityDashboardsTableColumns = (): Array< name: i18n.DASHBOARD_TITLE, sortable: true, render: (title: string, { id }) => { - const href = dashboard?.locator?.getRedirectUrl({ dashboardId: id }); + const href = `${getSecuritySolutionUrl({ + deepLinkId: SecurityPageName.dashboards, + path: id, + })}`; return href ? ( {title} @@ -90,7 +97,7 @@ export const useSecurityDashboardsTableColumns = (): Array< // adds the tags table column based on the saved object items ...(savedObjectsTagging ? [savedObjectsTagging.ui.getTableColumnDefinition()] : []), ], - [getNavigationHandler, dashboard, savedObjectsTagging] + [savedObjectsTagging, getSecuritySolutionUrl, getNavigationHandler] ); return columns; diff --git a/x-pack/plugins/security_solution/public/common/links/app_links.ts b/x-pack/plugins/security_solution/public/common/links/app_links.ts index c00fa87f878da..51f40c692e8cb 100644 --- a/x-pack/plugins/security_solution/public/common/links/app_links.ts +++ b/x-pack/plugins/security_solution/public/common/links/app_links.ts @@ -11,10 +11,11 @@ import { links as detectionLinks } from '../../detections/links'; import { links as timelinesLinks } from '../../timelines/links'; import { getCasesLinkItems } from '../../cases/links'; import { links as managementLinks, getManagementFilteredLinks } from '../../management/links'; -import { dashboardsLandingLinks, threatHuntingLandingLinks } from '../../landing_pages/links'; +import { threatHuntingLandingLinks } from '../../landing_pages/links'; import { gettingStartedLinks } from '../../overview/links'; import { rootLinks as cloudSecurityPostureRootLinks } from '../../cloud_security_posture/links'; import type { StartPlugins } from '../../types'; +import { dashboardsLandingLinks } from '../../dashboards/links'; const casesLinks = getCasesLinkItems(); diff --git a/x-pack/plugins/security_solution/public/common/utils/route/types.ts b/x-pack/plugins/security_solution/public/common/utils/route/types.ts index 93aee6676b47e..6e10a6f0d0c86 100644 --- a/x-pack/plugins/security_solution/public/common/utils/route/types.ts +++ b/x-pack/plugins/security_solution/public/common/utils/route/types.ts @@ -35,6 +35,7 @@ export type RouteSpyState = | GenericRouteSpyState | GenericRouteSpyState | GenericRouteSpyState + | GenericRouteSpyState | GenericRouteSpyState< Exclude< SecurityPageName, @@ -59,6 +60,7 @@ export type AdministrationRouteSpyState = GenericRouteSpyState< SecurityPageName.administration, AdministrationType >; +export type DashboardsRouteSpyState = GenericRouteSpyState; export type RouteSpyAction = | { diff --git a/x-pack/plugins/security_solution/public/dashboards/components/edit_dashboard_button.test.tsx b/x-pack/plugins/security_solution/public/dashboards/components/edit_dashboard_button.test.tsx new file mode 100644 index 0000000000000..e4cd6fa206929 --- /dev/null +++ b/x-pack/plugins/security_solution/public/dashboards/components/edit_dashboard_button.test.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 { render } from '@testing-library/react'; +import React from 'react'; +import { useKibana } from '../../common/lib/kibana'; +import { createStartServicesMock } from '../../common/lib/kibana/kibana_react.mock'; +import { TestProviders } from '../../common/mock/test_providers'; +import { EditDashboardButton } from './edit_dashboard_button'; + +jest.mock('../../common/lib/kibana/kibana_react', () => { + return { + useKibana: jest.fn(), + }; +}); + +describe('EditDashboardButton', () => { + const timeRange = { + from: '2023-03-24T00:00:00.000Z', + to: '2023-03-24T23:59:59.999Z', + }; + + beforeAll(() => { + (useKibana as jest.Mock).mockReturnValue({ + services: createStartServicesMock(), + }); + }); + + it('should render', () => { + const { queryByTestId } = render( + + + + ); + expect(queryByTestId('dashboardEditButton')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/dashboards/components/edit_dashboard_button.tsx b/x-pack/plugins/security_solution/public/dashboards/components/edit_dashboard_button.tsx new file mode 100644 index 0000000000000..c1089e95787e0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/dashboards/components/edit_dashboard_button.tsx @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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 type { Query, Filter } from '@kbn/es-query'; +import { EuiButton } from '@elastic/eui'; +import { useDashboardAppLink } from '../hooks/use_dashboard_app_link'; +import { EDIT_DASHBOARD_BUTTON_TITLE } from '../pages/details/translations'; +import { useKibana } from '../../common/lib/kibana'; + +export interface EditDashboardButtonComponentProps { + filters?: Filter[]; + query?: Query; + savedObjectId: string | undefined; + timeRange: { + from: string; + to: string; + fromStr?: string | undefined; + toStr?: string | undefined; + }; +} + +const EditDashboardButtonComponent: React.FC = ({ + filters, + query, + savedObjectId, + timeRange, +}) => { + const { + services: { uiSettings }, + } = useKibana(); + + const { onClick } = useDashboardAppLink({ + query, + filters, + timeRange, + uiSettings, + savedObjectId, + }); + + return ( + + {EDIT_DASHBOARD_BUTTON_TITLE} + + ); +}; + +EditDashboardButtonComponent.displayName = 'EditDashboardComponent'; +export const EditDashboardButton = React.memo(EditDashboardButtonComponent); diff --git a/x-pack/plugins/security_solution/public/dashboards/components/status_prompt.test.tsx b/x-pack/plugins/security_solution/public/dashboards/components/status_prompt.test.tsx new file mode 100644 index 0000000000000..c173aa836af55 --- /dev/null +++ b/x-pack/plugins/security_solution/public/dashboards/components/status_prompt.test.tsx @@ -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 { render } from '@testing-library/react'; +import React from 'react'; +import { DashboardViewPromptState } from '../hooks/use_dashboard_view_prompt_state'; +import { StatusPropmpt } from './status_prompt'; + +describe('StatusPropmpt', () => { + it('hides by default', () => { + const { queryByTestId } = render(); + expect(queryByTestId(`dashboardViewEmptyDefault`)).not.toBeInTheDocument(); + }); + + it('shows when No Read Permission', () => { + const { queryByTestId } = render( + + ); + + expect( + queryByTestId(`dashboardViewEmpty${DashboardViewPromptState.NoReadPermission}`) + ).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/dashboards/components/status_prompt.tsx b/x-pack/plugins/security_solution/public/dashboards/components/status_prompt.tsx new file mode 100644 index 0000000000000..7f0584ec0e882 --- /dev/null +++ b/x-pack/plugins/security_solution/public/dashboards/components/status_prompt.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 from 'react'; +import { EuiPageTemplate } from '@elastic/eui'; +import type { DashboardViewPromptState } from '../hooks/use_dashboard_view_prompt_state'; +import { useDashboardViewPromptState } from '../hooks/use_dashboard_view_prompt_state'; + +const StatusPropmptComponent = ({ + currentState, +}: { + currentState: DashboardViewPromptState | null; +}) => { + const emptyPromptProps = useDashboardViewPromptState(currentState); + return emptyPromptProps && currentState ? ( + + + + ) : null; +}; +StatusPropmptComponent.displayName = 'StatusPropmptComponent'; +export const StatusPropmpt = React.memo(StatusPropmptComponent); diff --git a/x-pack/plugins/security_solution/public/dashboards/hooks/use_dashboard_app_link.test.tsx b/x-pack/plugins/security_solution/public/dashboards/hooks/use_dashboard_app_link.test.tsx new file mode 100644 index 0000000000000..decd108b6d6af --- /dev/null +++ b/x-pack/plugins/security_solution/public/dashboards/hooks/use_dashboard_app_link.test.tsx @@ -0,0 +1,133 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { renderHook } from '@testing-library/react-hooks'; +import { useNavigation } from '../../common/lib/kibana'; +import { TestProviders } from '../../common/mock'; +import type { UseDashboardAppLinkProps } from './use_dashboard_app_link'; +import { useDashboardAppLink } from './use_dashboard_app_link'; + +jest.mock('../../common/lib/kibana', () => ({ + useNavigation: jest.fn(), +})); + +describe('useDashboardAppLink', () => { + const mockNavigateTo = jest.fn(); + const filters = [ + { + meta: { + index: 'security-solution-default', + type: 'phrase', + key: 'event.action', + params: { + query: 'host', + }, + disabled: false, + negate: false, + alias: null, + }, + query: { + match_phrase: { + 'event.action': 'host', + }, + }, + $state: { + store: 'appState', + }, + }, + ]; + const props = { + query: { + language: 'kuery', + query: '', + }, + filters: [], + timeRange: { + from: '2023-03-24T00:00:00.000Z', + fromStr: 'now/d', + to: '2023-03-24T23:59:59.999Z', + toStr: 'now/d', + }, + uiSettings: { + get: jest.fn(), + }, + savedObjectId: 'e2937420-c8ba-11ed-a7eb-3d08ee4d53cb', + }; + + beforeEach(() => { + jest.clearAllMocks(); + (useNavigation as jest.Mock).mockReturnValue({ + getAppUrl: jest + .fn() + .mockReturnValue('/app/dashboards#/view/e2937420-c8ba-11ed-a7eb-3d08ee4d53cb'), + navigateTo: mockNavigateTo, + }); + }); + it('create links to Dashboard app - with filters', () => { + const testProps = { ...props, filters } as unknown as UseDashboardAppLinkProps; + + const { result } = renderHook(() => useDashboardAppLink(testProps), { + wrapper: TestProviders, + }); + expect(result.current.href).toMatchInlineSnapshot( + `"/app/dashboards#/view/e2937420-c8ba-11ed-a7eb-3d08ee4d53cb?_g=(filters:!(('$state':(store:appState),meta:(alias:!n,disabled:!f,index:security-solution-default,key:event.action,negate:!f,params:(query:host),type:phrase),query:(match_phrase:(event.action:host)))),query:(language:kuery,query:''),time:(from:now%2Fd,to:now%2Fd))"` + ); + }); + + it('create links to Dashboard app - with query', () => { + const testProps = { + ...props, + query: { + language: 'kuery', + query: '@timestamp : *', + }, + } as unknown as UseDashboardAppLinkProps; + + const { result } = renderHook(() => useDashboardAppLink(testProps), { wrapper: TestProviders }); + expect(result.current.href).toMatchInlineSnapshot( + `"/app/dashboards#/view/e2937420-c8ba-11ed-a7eb-3d08ee4d53cb?_g=(filters:!(),query:(language:kuery,query:'@timestamp%20:%20*'),time:(from:now%2Fd,to:now%2Fd))"` + ); + }); + + it('create links to Dashboard app - with absolute time', () => { + const testProps = { + ...props, + timeRange: { + from: '2023-03-24T00:00:00.000Z', + to: '2023-03-24T23:59:59.999Z', + }, + } as unknown as UseDashboardAppLinkProps; + + const { result } = renderHook(() => useDashboardAppLink(testProps), { wrapper: TestProviders }); + expect(result.current.href).toMatchInlineSnapshot( + `"/app/dashboards#/view/e2937420-c8ba-11ed-a7eb-3d08ee4d53cb?_g=(filters:!(),query:(language:kuery,query:''),time:(from:'2023-03-24T00:00:00.000Z',to:'2023-03-24T23:59:59.999Z'))"` + ); + }); + + it('navigate to dashboard app with preserved states', () => { + const testProps = { + ...props, + timeRange: { + from: '2023-03-24T00:00:00.000Z', + to: '2023-03-24T23:59:59.999Z', + }, + } as unknown as UseDashboardAppLinkProps; + + const { result } = renderHook(() => useDashboardAppLink(testProps), { + wrapper: TestProviders, + }); + result.current.onClick({ + preventDefault: jest.fn(), + } as unknown as React.MouseEvent); + + expect(mockNavigateTo).toHaveBeenCalledWith( + expect.objectContaining({ + url: "/app/dashboards#/view/e2937420-c8ba-11ed-a7eb-3d08ee4d53cb?_g=(filters:!(),query:(language:kuery,query:''),time:(from:'2023-03-24T00:00:00.000Z',to:'2023-03-24T23:59:59.999Z'))", + }) + ); + }); +}); diff --git a/x-pack/plugins/security_solution/public/dashboards/hooks/use_dashboard_app_link.tsx b/x-pack/plugins/security_solution/public/dashboards/hooks/use_dashboard_app_link.tsx new file mode 100644 index 0000000000000..1bf8a16f1ce19 --- /dev/null +++ b/x-pack/plugins/security_solution/public/dashboards/hooks/use_dashboard_app_link.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createDashboardEditUrl, DASHBOARD_APP_ID } from '@kbn/dashboard-plugin/public'; +import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; +import type { IUiSettingsClient } from '@kbn/core/public'; +import { useMemo } from 'react'; +import type { Filter, Query } from '@kbn/es-query'; +import { useNavigation } from '../../common/lib/kibana'; + +const GLOBAL_STATE_STORAGE_KEY = '_g'; + +export interface UseDashboardAppLinkProps { + query?: Query; + filters?: Filter[]; + timeRange: { + from: string; + to: string; + fromStr?: string | undefined; + toStr?: string | undefined; + }; + uiSettings: IUiSettingsClient; + savedObjectId: string | undefined; +} + +export const useDashboardAppLink = ({ + query, + filters, + timeRange: { from, fromStr, to, toStr }, + uiSettings, + savedObjectId, +}: UseDashboardAppLinkProps) => { + const { navigateTo, getAppUrl } = useNavigation(); + const useHash = uiSettings.get('state:storeInSessionStorage'); + + let editDashboardUrl = useMemo( + () => + getAppUrl({ + appId: DASHBOARD_APP_ID, + path: `#${createDashboardEditUrl(savedObjectId)}`, + }), + [getAppUrl, savedObjectId] + ); + + editDashboardUrl = setStateToKbnUrl( + GLOBAL_STATE_STORAGE_KEY, + { + time: { from: fromStr ?? from, to: toStr ?? to }, + filters, + query, + }, + { useHash, storeInHashQuery: true }, + editDashboardUrl + ); + + const editDashboardLinkProps = useMemo( + () => ({ + onClick: (ev: React.MouseEvent) => { + ev.preventDefault(); + navigateTo({ url: editDashboardUrl }); + }, + href: editDashboardUrl, + }), + [editDashboardUrl, navigateTo] + ); + return editDashboardLinkProps; +}; diff --git a/x-pack/plugins/security_solution/public/dashboards/hooks/use_dashboard_view_prompt_state.test.tsx b/x-pack/plugins/security_solution/public/dashboards/hooks/use_dashboard_view_prompt_state.test.tsx new file mode 100644 index 0000000000000..b309d0a646a58 --- /dev/null +++ b/x-pack/plugins/security_solution/public/dashboards/hooks/use_dashboard_view_prompt_state.test.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { EuiEmptyPromptProps } from '@elastic/eui'; +import { renderHook } from '@testing-library/react-hooks'; +import { + DashboardViewPromptState, + useDashboardViewPromptState, +} from './use_dashboard_view_prompt_state'; + +describe('useDashboardViewPromptState', () => { + it('returns empty state', () => { + const { result } = renderHook< + DashboardViewPromptState | null, + Partial | null + >(() => useDashboardViewPromptState(null)); + expect(result.current).toBeNull(); + }); + + it('returns NoReadPermission state', () => { + const { result } = renderHook< + DashboardViewPromptState | null, + Partial | null + >(() => useDashboardViewPromptState(DashboardViewPromptState.NoReadPermission)); + expect(result.current).toMatchInlineSnapshot(` + Object { + "body":

+ Contact your administrator for help. +

, + "color": "danger", + "iconType": "error", + "title":

+ You have no permission to read the dashboard +

, + } + `); + }); + + it('returns IndicesNotFound state', () => { + const { result } = renderHook< + DashboardViewPromptState | null, + Partial | null + >(() => useDashboardViewPromptState(DashboardViewPromptState.IndicesNotFound)); + expect(result.current).toMatchInlineSnapshot(` + Object { + "color": "danger", + "iconType": "error", + "title":

+ Indices not found +

, + } + `); + }); +}); diff --git a/x-pack/plugins/security_solution/public/dashboards/hooks/use_dashboard_view_prompt_state.tsx b/x-pack/plugins/security_solution/public/dashboards/hooks/use_dashboard_view_prompt_state.tsx new file mode 100644 index 0000000000000..20c0be416bb3d --- /dev/null +++ b/x-pack/plugins/security_solution/public/dashboards/hooks/use_dashboard_view_prompt_state.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 type { EuiEmptyPromptProps } from '@elastic/eui'; +import * as i18n from '../pages/details/translations'; + +export enum DashboardViewPromptState { + NoReadPermission = 'NoReadPermission', + IndicesNotFound = 'IndicesNotFound', +} + +const dashboardViewPromptState: Record> = { + [DashboardViewPromptState.NoReadPermission]: { + color: 'danger', + iconType: 'error', + title:

{i18n.DASHBOARD_NO_READ_PERMISSION_TITLE}

, + body:

{i18n.DASHBOARD_NO_READ_PERMISSION_DESCRIPTION}

, + }, + [DashboardViewPromptState.IndicesNotFound]: { + color: 'danger', + iconType: 'error', + title:

{i18n.DASHBOARD_INDICES_NOT_FOUND_TITLE}

, + }, +}; + +export const useDashboardViewPromptState = ( + currentState: DashboardViewPromptState | null +): Partial | null => { + return currentState ? dashboardViewPromptState[currentState] : null; +}; diff --git a/x-pack/plugins/security_solution/public/common/components/page_route/index.tsx b/x-pack/plugins/security_solution/public/dashboards/index.ts similarity index 54% rename from x-pack/plugins/security_solution/public/common/components/page_route/index.tsx rename to x-pack/plugins/security_solution/public/dashboards/index.ts index c52227eba107a..1af6a985be8a8 100644 --- a/x-pack/plugins/security_solution/public/common/components/page_route/index.tsx +++ b/x-pack/plugins/security_solution/public/dashboards/index.ts @@ -4,5 +4,15 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import type { SecuritySubPlugin } from '../app/types'; +import { routes } from './routes'; -export { PageRoute } from './pageroute'; +export class Dashboards { + public setup() {} + + public start(): SecuritySubPlugin { + return { + routes, + }; + } +} diff --git a/x-pack/plugins/security_solution/public/dashboards/jest.config.js b/x-pack/plugins/security_solution/public/dashboards/jest.config.js new file mode 100644 index 0000000000000..a2ff7b5c4a1af --- /dev/null +++ b/x-pack/plugins/security_solution/public/dashboards/jest.config.js @@ -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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: ['/x-pack/plugins/security_solution/public/dashboards'], + coverageDirectory: + '/target/kibana-coverage/jest/x-pack/plugins/security_solution/public/dashboards', + coverageReporters: ['text', 'html'], + collectCoverageFrom: [ + '/x-pack/plugins/security_solution/public/dashboards/**/*.{ts,tsx}', + ], + moduleNameMapper: require('../../server/__mocks__/module_name_map'), +}; diff --git a/x-pack/plugins/security_solution/public/dashboards/links.ts b/x-pack/plugins/security_solution/public/dashboards/links.ts new file mode 100644 index 0000000000000..452b03444988e --- /dev/null +++ b/x-pack/plugins/security_solution/public/dashboards/links.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 { i18n } from '@kbn/i18n'; +import { DASHBOARDS_PATH, SecurityPageName, SERVER_APP_ID } from '../../common/constants'; +import { DASHBOARDS } from '../app/translations'; +import type { LinkItem } from '../common/links/types'; +import { links as kubernetesLinks } from '../kubernetes/links'; +import { dashboardLinks as cloudSecurityPostureLinks } from '../cloud_security_posture/links'; +import { + ecsDataQualityDashboardLinks, + detectionResponseLinks, + entityAnalyticsLinks, + overviewLinks, +} from '../overview/links'; + +export const dashboardsLandingLinks: LinkItem = { + id: SecurityPageName.dashboards, + title: DASHBOARDS, + path: DASHBOARDS_PATH, + globalNavPosition: 1, + capabilities: [`${SERVER_APP_ID}.show`], + globalSearchKeywords: [ + i18n.translate('xpack.securitySolution.appLinks.dashboards', { + defaultMessage: 'Dashboards', + }), + ], + links: [ + overviewLinks, + detectionResponseLinks, + kubernetesLinks, + cloudSecurityPostureLinks, + entityAnalyticsLinks, + ecsDataQualityDashboardLinks, + ], + skipUrlState: false, +}; diff --git a/x-pack/plugins/security_solution/public/dashboards/pages/details/index.tsx b/x-pack/plugins/security_solution/public/dashboards/pages/details/index.tsx new file mode 100644 index 0000000000000..124ebb67339c9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/dashboards/pages/details/index.tsx @@ -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 React, { useState, useCallback, useEffect, useMemo } from 'react'; +import { LEGACY_DASHBOARD_APP_ID } from '@kbn/dashboard-plugin/public'; +import type { DashboardContainer } from '@kbn/dashboard-plugin/public'; + +import type { DashboardCapabilities } from '@kbn/dashboard-plugin/common/types'; +import { useParams } from 'react-router-dom'; + +import { isEmpty, pick } from 'lodash/fp'; +import { SecurityPageName } from '../../../../common/constants'; +import { SpyRoute } from '../../../common/utils/route/spy_routes'; +import { useCapabilities } from '../../../common/lib/kibana'; +import { DashboardViewPromptState } from '../../hooks/use_dashboard_view_prompt_state'; +import { DashboardRenderer } from '../../../common/components/dashboards/dashboard_renderer'; +import { StatusPropmpt } from '../../components/status_prompt'; +import { SiemSearchBar } from '../../../common/components/search_bar'; +import { SecuritySolutionPageWrapper } from '../../../common/components/page_wrapper'; +import { FiltersGlobal } from '../../../common/components/filters_global'; +import { InputsModelId } from '../../../common/store/inputs/constants'; +import { useSourcererDataView } from '../../../common/containers/sourcerer'; +import { HeaderPage } from '../../../common/components/header_page'; +import { DASHBOARD_PAGE_TITLE } from '../translations'; +import { inputsSelectors } from '../../../common/store'; +import { useDeepEqualSelector } from '../../../common/hooks/use_selector'; +import { EditDashboardButton } from '../../components/edit_dashboard_button'; + +type DashboardDetails = Record; + +const DashboardViewComponent: React.FC = () => { + const { fromStr, toStr, from, to } = useDeepEqualSelector((state) => + pick(['fromStr', 'toStr', 'from', 'to'], inputsSelectors.globalTimeRangeSelector(state)) + ); + const timeRange = useMemo(() => ({ from, to, fromStr, toStr }), [from, fromStr, to, toStr]); + const getGlobalQuerySelector = useMemo(() => inputsSelectors.globalQuerySelector(), []); + const getGlobalFiltersQuerySelector = useMemo( + () => inputsSelectors.globalFiltersQuerySelector(), + [] + ); + const query = useDeepEqualSelector(getGlobalQuerySelector); + const filters = useDeepEqualSelector(getGlobalFiltersQuerySelector); + const { indexPattern, indicesExist } = useSourcererDataView(); + + const { show: canReadDashboard, showWriteControls } = + useCapabilities(LEGACY_DASHBOARD_APP_ID); + const [currentState, setCurrentState] = useState( + canReadDashboard ? null : DashboardViewPromptState.NoReadPermission + ); + const [dashboardDetails, setDashboardDetails] = useState(); + const onDashboardContainerLoaded = useCallback((dashboardContainer: DashboardContainer) => { + const dashboardTitle = dashboardContainer.getTitle().trim(); + setDashboardDetails({ dashboardTitle }); + }, []); + const { detailName: savedObjectId } = useParams<{ detailName?: string }>(); + const dashboardExists = !isEmpty(dashboardDetails?.dashboardTitle); + + useEffect(() => { + if (!indicesExist) { + setCurrentState(DashboardViewPromptState.IndicesNotFound); + } + }, [indicesExist]); + + return ( + <> + {indicesExist && ( + + + + )} + + + {showWriteControls && dashboardExists && ( + + )} + + + {indicesExist && ( + + )} + + + + + + ); +}; +DashboardViewComponent.displayName = 'DashboardViewComponent'; +export const DashboardView = React.memo(DashboardViewComponent); diff --git a/x-pack/plugins/security_solution/public/dashboards/pages/details/translations.ts b/x-pack/plugins/security_solution/public/dashboards/pages/details/translations.ts new file mode 100644 index 0000000000000..dfd25dcbe8512 --- /dev/null +++ b/x-pack/plugins/security_solution/public/dashboards/pages/details/translations.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 { i18n } from '@kbn/i18n'; + +export const DASHBOARD_NO_READ_PERMISSION_TITLE = i18n.translate( + 'xpack.securitySolution.dashboards.dashboard.viewPorpmpt.noReadPermission.title', + { + defaultMessage: 'You have no permission to read the dashboard', + } +); + +export const DASHBOARD_NO_READ_PERMISSION_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.dashboards.dashboard.viewPorpmpt.noReadPermission.description', + { + defaultMessage: 'Contact your administrator for help.', + } +); + +export const DASHBOARD_INDICES_NOT_FOUND_TITLE = i18n.translate( + 'xpack.securitySolution.dashboards.dashboard.viewPorpmpt.indicesNotFound.title', + { + defaultMessage: 'Indices not found', + } +); + +export const EDIT_DASHBOARD_BUTTON_TITLE = i18n.translate( + 'xpack.securitySolution.dashboards.dashboard.editDashboardButtonTitle', + { + defaultMessage: `Edit`, + } +); diff --git a/x-pack/plugins/security_solution/public/dashboards/pages/index.tsx b/x-pack/plugins/security_solution/public/dashboards/pages/index.tsx new file mode 100644 index 0000000000000..bf837291a151e --- /dev/null +++ b/x-pack/plugins/security_solution/public/dashboards/pages/index.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 { Switch } from 'react-router-dom'; +import { Route } from '@kbn/shared-ux-router'; + +import { DashboardsLandingPage } from './landing_page'; +import { DashboardView } from './details'; +import { DASHBOARDS_PATH } from '../../../common/constants'; + +const DashboardsContainerComponent = () => { + return ( + + + + + + + + + ); +}; +export const DashboardsContainer = React.memo(DashboardsContainerComponent); diff --git a/x-pack/plugins/security_solution/public/landing_pages/pages/dashboards.test.tsx b/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.test.tsx similarity index 85% rename from x-pack/plugins/security_solution/public/landing_pages/pages/dashboards.test.tsx rename to x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.test.tsx index 97eb89695bc98..bfc035a0add12 100644 --- a/x-pack/plugins/security_solution/public/landing_pages/pages/dashboards.test.tsx +++ b/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.test.tsx @@ -7,16 +7,16 @@ import { render } from '@testing-library/react'; import React from 'react'; -import { SecurityPageName } from '../../app/types'; -import { TestProviders } from '../../common/mock'; -import { DashboardsLandingPage } from './dashboards'; -import type { NavLinkItem } from '../../common/components/navigation/types'; -import { useCapabilities } from '../../common/lib/kibana'; -import * as telemetry from '../../common/lib/telemetry'; - -jest.mock('../../common/lib/kibana'); -jest.mock('../../common/utils/route/spy_routes', () => ({ SpyRoute: () => null })); -jest.mock('../../common/components/dashboards/dashboards_table', () => ({ +import { SecurityPageName } from '../../../app/types'; +import { TestProviders } from '../../../common/mock'; +import { DashboardsLandingPage } from '.'; +import type { NavLinkItem } from '../../../common/components/navigation/types'; +import { useCapabilities } from '../../../common/lib/kibana'; +import * as telemetry from '../../../common/lib/telemetry'; + +jest.mock('../../../common/lib/kibana'); +jest.mock('../../../common/utils/route/spy_routes', () => ({ SpyRoute: () => null })); +jest.mock('../../../common/components/dashboards/dashboards_table', () => ({ DashboardsTable: () => , })); @@ -29,7 +29,7 @@ const OVERVIEW_ITEM_LABEL = 'Overview'; const DETECTION_RESPONSE_ITEM_LABEL = 'Detection & Response'; const APP_DASHBOARD_LINKS: NavLinkItem = { - id: SecurityPageName.dashboardsLanding, + id: SecurityPageName.dashboards, title: 'Dashboards', links: [ { @@ -49,15 +49,15 @@ const APP_DASHBOARD_LINKS: NavLinkItem = { const URL = '/path/to/dashboards'; const mockAppManageLink = jest.fn(() => APP_DASHBOARD_LINKS); -jest.mock('../../common/components/navigation/nav_links', () => ({ +jest.mock('../../../common/components/navigation/nav_links', () => ({ useAppRootNavLink: () => mockAppManageLink(), })); const CREATE_DASHBOARD_LINK = { isLoading: false, url: URL }; const mockUseCreateSecurityDashboard = jest.fn(() => CREATE_DASHBOARD_LINK); -jest.mock('../../common/containers/dashboards/use_create_security_dashboard_link', () => { +jest.mock('../../../common/containers/dashboards/use_create_security_dashboard_link', () => { const actual = jest.requireActual( - '../../common/containers/dashboards/use_create_security_dashboard_link' + '../../../common/containers/dashboards/use_create_security_dashboard_link' ); return { ...actual, diff --git a/x-pack/plugins/security_solution/public/landing_pages/pages/dashboards.tsx b/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.tsx similarity index 63% rename from x-pack/plugins/security_solution/public/landing_pages/pages/dashboards.tsx rename to x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.tsx index ee97955b659ab..d6d9be365fc30 100644 --- a/x-pack/plugins/security_solution/public/landing_pages/pages/dashboards.tsx +++ b/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.tsx @@ -4,47 +4,41 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { - EuiButton, - EuiFlexGroup, - EuiFlexItem, - EuiHorizontalRule, - EuiSpacer, - EuiTitle, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiSpacer, EuiTitle } from '@elastic/eui'; import React from 'react'; import type { DashboardCapabilities } from '@kbn/dashboard-plugin/common/types'; import { LEGACY_DASHBOARD_APP_ID } from '@kbn/dashboard-plugin/public'; -import { SecurityPageName } from '../../app/types'; -import { DashboardsTable } from '../../common/components/dashboards/dashboards_table'; -import { Title } from '../../common/components/header_page/title'; -import { useAppRootNavLink } from '../../common/components/navigation/nav_links'; -import { SecuritySolutionPageWrapper } from '../../common/components/page_wrapper'; -import { useCreateSecurityDashboardLink } from '../../common/containers/dashboards/use_create_security_dashboard_link'; -import { useCapabilities, useNavigateTo } from '../../common/lib/kibana'; -import { SpyRoute } from '../../common/utils/route/spy_routes'; -import { LandingImageCards } from '../components/landing_links_images'; +import { SecuritySolutionPageWrapper } from '../../../common/components/page_wrapper'; +import { SpyRoute } from '../../../common/utils/route/spy_routes'; +import { DashboardsTable } from '../../../common/components/dashboards/dashboards_table'; +import { LandingImageCards } from '../../../landing_pages/components/landing_links_images'; +import { SecurityPageName } from '../../../../common/constants'; +import { useCapabilities, useNavigateTo } from '../../../common/lib/kibana'; +import { useAppRootNavLink } from '../../../common/components/navigation/nav_links'; +import { useCreateSecurityDashboardLink } from '../../../common/containers/dashboards/use_create_security_dashboard_link'; +import { Title } from '../../../common/components/header_page/title'; +import { LinkButton } from '../../../common/components/links/helpers'; import * as i18n from './translations'; -import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../common/lib/telemetry'; +import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../../common/lib/telemetry'; +import { DASHBOARDS_PAGE_TITLE } from '../translations'; -/* eslint-disable @elastic/eui/href-or-on-click */ const Header: React.FC<{ canCreateDashboard: boolean }> = ({ canCreateDashboard }) => { const { isLoading, url } = useCreateSecurityDashboardLink(); const { navigateTo } = useNavigateTo(); return ( - + <Title title={DASHBOARDS_PAGE_TITLE} /> </EuiFlexItem> {canCreateDashboard && ( <EuiFlexItem grow={false}> - <EuiButton + <LinkButton isDisabled={isLoading} color="primary" fill iconType="plusInCircle" href={url} - onClick={(ev) => { + onClick={(ev: React.MouseEvent<HTMLButtonElement>) => { ev.preventDefault(); track(METRIC_TYPE.CLICK, `${TELEMETRY_EVENT.CREATE_DASHBOARD}`); navigateTo({ url }); @@ -52,7 +46,7 @@ const Header: React.FC<{ canCreateDashboard: boolean }> = ({ canCreateDashboard data-test-subj="createDashboardButton" > {i18n.DASHBOARDS_PAGE_CREATE_BUTTON} - </EuiButton> + </LinkButton> </EuiFlexItem> )} </EuiFlexGroup> @@ -60,7 +54,7 @@ const Header: React.FC<{ canCreateDashboard: boolean }> = ({ canCreateDashboard }; export const DashboardsLandingPage = () => { - const dashboardLinks = useAppRootNavLink(SecurityPageName.dashboardsLanding)?.links ?? []; + const dashboardLinks = useAppRootNavLink(SecurityPageName.dashboards)?.links ?? []; const { show: canReadDashboard, createNew: canCreateDashboard } = useCapabilities<DashboardCapabilities>(LEGACY_DASHBOARD_APP_ID); @@ -87,7 +81,7 @@ export const DashboardsLandingPage = () => { </> )} - <SpyRoute pageName={SecurityPageName.dashboardsLanding} /> + <SpyRoute pageName={SecurityPageName.dashboards} /> </SecuritySolutionPageWrapper> ); }; diff --git a/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/translations.ts b/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/translations.ts new file mode 100644 index 0000000000000..71bafc6a80990 --- /dev/null +++ b/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/translations.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 { i18n } from '@kbn/i18n'; + +export const DASHBOARDS_PAGE_CREATE_BUTTON = i18n.translate( + 'xpack.securitySolution.dashboards.landing.createButton', + { + defaultMessage: 'Create Dashboard', + } +); + +export const DASHBOARDS_PAGE_SECTION_DEFAULT = i18n.translate( + 'xpack.securitySolution.dashboards.landing.section.default', + { + defaultMessage: 'DEFAULT', + } +); + +export const DASHBOARDS_PAGE_SECTION_CUSTOM = i18n.translate( + 'xpack.securitySolution.dashboards.landing.section.custom', + { + defaultMessage: 'CUSTOM', + } +); diff --git a/x-pack/plugins/security_solution/public/dashboards/pages/translations.ts b/x-pack/plugins/security_solution/public/dashboards/pages/translations.ts new file mode 100644 index 0000000000000..716b5a6d3a81d --- /dev/null +++ b/x-pack/plugins/security_solution/public/dashboards/pages/translations.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 { i18n } from '@kbn/i18n'; + +export const DASHBOARDS_PAGE_TITLE = i18n.translate('xpack.securitySolution.dashboards.pageTitle', { + defaultMessage: 'Dashboards', +}); + +export const DASHBOARD_PAGE_TITLE = i18n.translate('xpack.securitySolution.dashboard.pageTitle', { + defaultMessage: 'Dashboard', +}); diff --git a/x-pack/plugins/security_solution/public/dashboards/pages/utils.ts b/x-pack/plugins/security_solution/public/dashboards/pages/utils.ts new file mode 100644 index 0000000000000..8db389553c523 --- /dev/null +++ b/x-pack/plugins/security_solution/public/dashboards/pages/utils.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 type { ChromeBreadcrumb } from '@kbn/core/public'; +import { isEmpty } from 'lodash/fp'; +import type { RouteSpyState } from '../../common/utils/route/types'; + +export const getTrailingBreadcrumbs = (params: RouteSpyState): ChromeBreadcrumb[] => { + let breadcrumb: ChromeBreadcrumb[] = []; + + const dashboardTitle = params?.state?.dashboardTitle?.trim(); + if (params?.state?.dashboardTitle || params.detailName) { + breadcrumb = [ + ...breadcrumb, + { + text: !isEmpty(dashboardTitle) ? dashboardTitle : params.detailName, + }, + ]; + } + + return breadcrumb; +}; diff --git a/x-pack/plugins/security_solution/public/dashboards/routes.tsx b/x-pack/plugins/security_solution/public/dashboards/routes.tsx new file mode 100644 index 0000000000000..b9e854dfdbbdf --- /dev/null +++ b/x-pack/plugins/security_solution/public/dashboards/routes.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 { TrackApplicationView } from '@kbn/usage-collection-plugin/public'; + +import { DASHBOARDS_PATH, SecurityPageName } from '../../common/constants'; +import type { SecuritySubPluginRoutes } from '../app/types'; +import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper'; +import { DashboardsContainer } from './pages'; + +export const DashboardRoutes = () => ( + <PluginTemplateWrapper> + <TrackApplicationView viewId={SecurityPageName.dashboards}> + <DashboardsContainer /> + </TrackApplicationView> + </PluginTemplateWrapper> +); + +export const routes: SecuritySubPluginRoutes = [ + { + path: DASHBOARDS_PATH, + component: DashboardRoutes, + }, +]; diff --git a/x-pack/plugins/security_solution/public/landing_pages/links.ts b/x-pack/plugins/security_solution/public/landing_pages/links.ts index adbb37a59de5b..081576bb7212e 100644 --- a/x-pack/plugins/security_solution/public/landing_pages/links.ts +++ b/x-pack/plugins/security_solution/public/landing_pages/links.ts @@ -6,45 +6,11 @@ */ import { i18n } from '@kbn/i18n'; -import { - DASHBOARDS_PATH, - EXPLORE_PATH, - SecurityPageName, - SERVER_APP_ID, -} from '../../common/constants'; -import { DASHBOARDS, EXPLORE } from '../app/translations'; +import { EXPLORE_PATH, SecurityPageName, SERVER_APP_ID } from '../../common/constants'; +import { EXPLORE } from '../app/translations'; import type { LinkItem } from '../common/links/types'; -import { - ecsDataQualityDashboardLinks, - detectionResponseLinks, - entityAnalyticsLinks, - overviewLinks, -} from '../overview/links'; -import { exploreLinks } from '../explore/links'; -import { links as kubernetesLinks } from '../kubernetes/links'; -import { dashboardLinks as cloudSecurityPostureLinks } from '../cloud_security_posture/links'; -export const dashboardsLandingLinks: LinkItem = { - id: SecurityPageName.dashboardsLanding, - title: DASHBOARDS, - path: DASHBOARDS_PATH, - globalNavPosition: 1, - capabilities: [`${SERVER_APP_ID}.show`], - globalSearchKeywords: [ - i18n.translate('xpack.securitySolution.appLinks.dashboards', { - defaultMessage: 'Dashboards', - }), - ], - links: [ - overviewLinks, - detectionResponseLinks, - kubernetesLinks, - cloudSecurityPostureLinks, - entityAnalyticsLinks, - ecsDataQualityDashboardLinks, - ], - skipUrlState: true, -}; +import { exploreLinks } from '../explore/links'; export const threatHuntingLandingLinks: LinkItem = { id: SecurityPageName.exploreLanding, diff --git a/x-pack/plugins/security_solution/public/landing_pages/pages/translations.ts b/x-pack/plugins/security_solution/public/landing_pages/pages/translations.ts index f911ea393c4d5..ab5ded43f234a 100644 --- a/x-pack/plugins/security_solution/public/landing_pages/pages/translations.ts +++ b/x-pack/plugins/security_solution/public/landing_pages/pages/translations.ts @@ -14,34 +14,6 @@ export const EXPLORE_PAGE_TITLE = i18n.translate( } ); -export const DASHBOARDS_PAGE_TITLE = i18n.translate( - 'xpack.securitySolution.landing.dashboards.pageTitle', - { - defaultMessage: 'Dashboards', - } -); - -export const DASHBOARDS_PAGE_CREATE_BUTTON = i18n.translate( - 'xpack.securitySolution.landing.dashboards.createButton', - { - defaultMessage: 'Create Dashboard', - } -); - -export const DASHBOARDS_PAGE_SECTION_DEFAULT = i18n.translate( - 'xpack.securitySolution.landing.dashboards.section.default', - { - defaultMessage: 'DEFAULT', - } -); - -export const DASHBOARDS_PAGE_SECTION_CUSTOM = i18n.translate( - 'xpack.securitySolution.landing.dashboards.section.custom', - { - defaultMessage: 'CUSTOM', - } -); - export const MANAGE_PAGE_TITLE = i18n.translate('xpack.securitySolution.landing.manage.pageTitle', { defaultMessage: 'Manage', }); diff --git a/x-pack/plugins/security_solution/public/landing_pages/routes.tsx b/x-pack/plugins/security_solution/public/landing_pages/routes.tsx index a9e7d9ddb27cb..62a07bea29491 100644 --- a/x-pack/plugins/security_solution/public/landing_pages/routes.tsx +++ b/x-pack/plugins/security_solution/public/landing_pages/routes.tsx @@ -10,9 +10,8 @@ import { TrackApplicationView } from '@kbn/usage-collection-plugin/public'; import type { SecuritySubPluginRoutes } from '../app/types'; import { SecurityPageName } from '../app/types'; -import { DASHBOARDS_PATH, MANAGE_PATH, EXPLORE_PATH } from '../../common/constants'; +import { MANAGE_PATH, EXPLORE_PATH } from '../../common/constants'; import { ExploreLandingPage } from './pages/explore'; -import { DashboardsLandingPage } from './pages/dashboards'; import { ManageLandingPage } from './pages/manage'; import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper'; @@ -24,14 +23,6 @@ export const ThreatHuntingRoutes = () => ( </PluginTemplateWrapper> ); -export const DashboardRoutes = () => ( - <PluginTemplateWrapper> - <TrackApplicationView viewId={SecurityPageName.dashboardsLanding}> - <DashboardsLandingPage /> - </TrackApplicationView> - </PluginTemplateWrapper> -); - export const ManageRoutes = () => ( <PluginTemplateWrapper> <TrackApplicationView viewId={SecurityPageName.administration}> @@ -45,10 +36,6 @@ export const routes: SecuritySubPluginRoutes = [ path: EXPLORE_PATH, component: ThreatHuntingRoutes, }, - { - path: DASHBOARDS_PATH, - component: DashboardRoutes, - }, { path: MANAGE_PATH, component: ManageRoutes, diff --git a/x-pack/plugins/security_solution/public/lazy_sub_plugins.tsx b/x-pack/plugins/security_solution/public/lazy_sub_plugins.tsx index 66aefc6db3e08..01cb1ff21bfe7 100644 --- a/x-pack/plugins/security_solution/public/lazy_sub_plugins.tsx +++ b/x-pack/plugins/security_solution/public/lazy_sub_plugins.tsx @@ -23,6 +23,7 @@ import { LandingPages } from './landing_pages'; import { CloudDefend } from './cloud_defend'; import { CloudSecurityPosture } from './cloud_security_posture'; import { ThreatIntelligence } from './threat_intelligence'; +import { Dashboards } from './dashboards'; /** * The classes used to instantiate the sub plugins. These are grouped into a single object for the sake of bundling them in a single dynamic import. @@ -38,6 +39,7 @@ const subPluginClasses = { Timelines, Management, LandingPages, + Dashboards, CloudDefend, CloudSecurityPosture, ThreatIntelligence, diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index 17ba2940e94d9..9553b2695f95c 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -399,6 +399,7 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S rules: new subPluginClasses.Rules(), exceptions: new subPluginClasses.Exceptions(), cases: new subPluginClasses.Cases(), + dashboards: new subPluginClasses.Dashboards(), explore: new subPluginClasses.Explore(), kubernetes: new subPluginClasses.Kubernetes(), overview: new subPluginClasses.Overview(), @@ -423,19 +424,20 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S ): Promise<StartedSubPlugins> { const subPlugins = await this.subPlugins(); return { - overview: subPlugins.overview.start(), alerts: subPlugins.alerts.start(storage), cases: subPlugins.cases.start(), - rules: subPlugins.rules.start(storage), + cloudDefend: subPlugins.cloudDefend.start(), + cloudSecurityPosture: subPlugins.cloudSecurityPosture.start(), + dashboards: subPlugins.dashboards.start(), exceptions: subPlugins.exceptions.start(storage), explore: subPlugins.explore.start(storage), - timelines: subPlugins.timelines.start(), kubernetes: subPlugins.kubernetes.start(), - management: subPlugins.management.start(core, plugins), landingPages: subPlugins.landingPages.start(), - cloudDefend: subPlugins.cloudDefend.start(), - cloudSecurityPosture: subPlugins.cloudSecurityPosture.start(), + management: subPlugins.management.start(core, plugins), + overview: subPlugins.overview.start(), + rules: subPlugins.rules.start(storage), threatIntelligence: subPlugins.threatIntelligence.start(), + timelines: subPlugins.timelines.start(), }; } /** diff --git a/x-pack/plugins/security_solution/public/types.ts b/x-pack/plugins/security_solution/public/types.ts index f1450738e8d36..a9566fabc6c1a 100644 --- a/x-pack/plugins/security_solution/public/types.ts +++ b/x-pack/plugins/security_solution/public/types.ts @@ -62,6 +62,8 @@ import type { ThreatIntelligence } from './threat_intelligence'; import type { SecuritySolutionTemplateWrapper } from './app/home/template_wrapper'; import type { Explore } from './explore'; import type { TelemetryClientStart } from './common/lib/telemetry'; +import type { Dashboards } from './dashboards'; + export interface SetupPlugins { home?: HomePublicPluginSetup; licensing: LicensingPluginSetup; @@ -139,34 +141,36 @@ export type InspectResponse = Inspect & { response: string[] }; export const CASES_SUB_PLUGIN_KEY = 'cases'; export interface SubPlugins { + [CASES_SUB_PLUGIN_KEY]: Cases; alerts: Detections; - rules: Rules; + cloudDefend: CloudDefend; + cloudSecurityPosture: CloudSecurityPosture; + dashboards: Dashboards; exceptions: Exceptions; - [CASES_SUB_PLUGIN_KEY]: Cases; explore: Explore; kubernetes: Kubernetes; - overview: Overview; - timelines: Timelines; - management: Management; landingPages: LandingPages; - cloudDefend: CloudDefend; - cloudSecurityPosture: CloudSecurityPosture; + management: Management; + overview: Overview; + rules: Rules; threatIntelligence: ThreatIntelligence; + timelines: Timelines; } // TODO: find a better way to defined these types export interface StartedSubPlugins { + [CASES_SUB_PLUGIN_KEY]: ReturnType<Cases['start']>; alerts: ReturnType<Detections['start']>; - rules: ReturnType<Rules['start']>; + cloudDefend: ReturnType<CloudDefend['start']>; + cloudSecurityPosture: ReturnType<CloudSecurityPosture['start']>; + dashboards: ReturnType<Dashboards['start']>; exceptions: ReturnType<Exceptions['start']>; - [CASES_SUB_PLUGIN_KEY]: ReturnType<Cases['start']>; explore: ReturnType<Explore['start']>; kubernetes: ReturnType<Kubernetes['start']>; - overview: ReturnType<Overview['start']>; - timelines: ReturnType<Timelines['start']>; - management: ReturnType<Management['start']>; landingPages: ReturnType<LandingPages['start']>; - cloudDefend: ReturnType<CloudDefend['start']>; - cloudSecurityPosture: ReturnType<CloudSecurityPosture['start']>; + management: ReturnType<Management['start']>; + overview: ReturnType<Overview['start']>; + rules: ReturnType<Rules['start']>; threatIntelligence: ReturnType<ThreatIntelligence['start']>; + timelines: ReturnType<Timelines['start']>; } diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index c7e399e6ed9ca..ceb82974f0d56 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -31392,10 +31392,6 @@ "xpack.securitySolution.kubernetes.columnNode": "Nœud", "xpack.securitySolution.kubernetes.columnPod": "Pod", "xpack.securitySolution.kubernetes.columnSessionStart": "Date de connexion", - "xpack.securitySolution.landing.dashboards.createButton": "Créer un tableau de bord", - "xpack.securitySolution.landing.dashboards.pageTitle": "Tableaux de bord", - "xpack.securitySolution.landing.dashboards.section.custom": "PERSONNALISÉ", - "xpack.securitySolution.landing.dashboards.section.default": "PAR DÉFAUT", "xpack.securitySolution.landing.manage.pageTitle": "Gérer", "xpack.securitySolution.landing.threatHunting.hostsDescription": "Aperçu complet de tous les hôtes et événements de sécurité des hôtes.", "xpack.securitySolution.landing.threatHunting.pageTitle": "Explorer", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 4e97d9a007e22..89a92f9c4ad21 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -31371,10 +31371,6 @@ "xpack.securitySolution.kubernetes.columnNode": "ノード", "xpack.securitySolution.kubernetes.columnPod": "ポッド", "xpack.securitySolution.kubernetes.columnSessionStart": "データが接続されました", - "xpack.securitySolution.landing.dashboards.createButton": "ダッシュボードを作成", - "xpack.securitySolution.landing.dashboards.pageTitle": "ダッシュボード", - "xpack.securitySolution.landing.dashboards.section.custom": "カスタム", - "xpack.securitySolution.landing.dashboards.section.default": "デフォルト", "xpack.securitySolution.landing.manage.pageTitle": "管理", "xpack.securitySolution.landing.threatHunting.hostsDescription": "すべてのホストとホスト関連のセキュリティイベントに関する包括的な概要。", "xpack.securitySolution.landing.threatHunting.pageTitle": "探索", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 5ac1921894867..2f50f22e0ce3b 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -31387,10 +31387,6 @@ "xpack.securitySolution.kubernetes.columnNode": "节点", "xpack.securitySolution.kubernetes.columnPod": "Pod", "xpack.securitySolution.kubernetes.columnSessionStart": "连接日期", - "xpack.securitySolution.landing.dashboards.createButton": "创建仪表板", - "xpack.securitySolution.landing.dashboards.pageTitle": "仪表板", - "xpack.securitySolution.landing.dashboards.section.custom": "定制", - "xpack.securitySolution.landing.dashboards.section.default": "默认", "xpack.securitySolution.landing.manage.pageTitle": "管理", "xpack.securitySolution.landing.threatHunting.hostsDescription": "所有主机和主机相关安全事件的全面概览。", "xpack.securitySolution.landing.threatHunting.pageTitle": "浏览", From ebac6946122355ab25b226642e5aa9dab7c7710b Mon Sep 17 00:00:00 2001 From: Nathan Reese <reese.nathan@elastic.co> Date: Tue, 11 Apr 2023 14:25:39 -0600 Subject: [PATCH 15/23] [maps] fix raster layer is missing in pdf/png exports (#154686) Fixes https://github.com/elastic/kibana/issues/154657 (Also heatmap layer has the same problem) ILayer has 2 methods to determine loading state: * isInitialDataLoadComplete * isLayerLoading When `isInitialDataLoadComplete` returns true for all layers, the map signals that it's ready for reports to be captured. The root cause of the problem is that the raster layer implementation did not provide an `isInitialDataLoadComplete` implementation for tiled maplibre sources. Therefore raster_tile_layer.ts would return true before all raster images are loaded, allowing reporting to capture an image with missing tiles. Having `isInitialDataLoadComplete` and `isLayerLoading` and spreading duplicate tiled implementations across layer classes contributed to the problem. PR: * removes `isInitialDataLoadComplete` from ILayer interface (supports long term goal of making ILayer simpler). * updates `isLayerLoading` to signal loading when layer is not initialized yet. This required calls to ensure layer is visible and displayed at zoom level before calling `isLayerLoading`, since `isLayerLoading` will now return true if no data has been loaded for a layer. * renames `areLayersLoaded` -> `isMapLoading` to be more symmetrical with ILayer.isLayerLoading method name and return value. <img width="400" alt="Screen Shot 2023-04-10 at 2 04 28 PM" src="https://user-images.githubusercontent.com/373691/230987781-2dfc68b7-f9bb-4ba6-8ab3-aaff5ea36859.png"> --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../ems_vector_tile_layer.test.ts | 14 ++++---- .../ems_vector_tile_layer.tsx | 5 +-- .../layers/heatmap_layer/heatmap_layer.ts | 5 +++ .../maps/public/classes/layers/layer.tsx | 28 +++++++++------ .../layers/layer_group/layer_group.tsx | 4 --- .../raster_tile_layer/raster_tile_layer.ts | 5 +++ .../geojson_vector_layer.tsx | 5 +++ .../mvt_vector_layer.test.tsx | 22 ++++++------ .../mvt_vector_layer/mvt_vector_layer.tsx | 7 ++-- .../layers/vector_layer/vector_layer.tsx | 21 +++++------ .../map_container/index.ts | 4 +-- .../map_container/map_container.tsx | 4 +-- .../layer_control/index.ts | 3 +- .../layer_control/layer_control.test.tsx | 10 ++++++ .../layer_control/layer_control.tsx | 4 ++- .../toc_entry_button/toc_entry_button.tsx | 16 ++++----- .../maps/public/embeddable/map_embeddable.tsx | 11 ++---- .../map_app/wait_until_time_layers_load.ts | 19 ++++++---- .../public/selectors/map_selectors.test.ts | 36 +++++++++---------- .../maps/public/selectors/map_selectors.ts | 29 +++++++++------ 20 files changed, 142 insertions(+), 110 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/layers/ems_vector_tile_layer/ems_vector_tile_layer.test.ts b/x-pack/plugins/maps/public/classes/layers/ems_vector_tile_layer/ems_vector_tile_layer.test.ts index 7f000804d91a5..acae0ca976fe5 100644 --- a/x-pack/plugins/maps/public/classes/layers/ems_vector_tile_layer/ems_vector_tile_layer.test.ts +++ b/x-pack/plugins/maps/public/classes/layers/ems_vector_tile_layer/ems_vector_tile_layer.test.ts @@ -75,33 +75,33 @@ describe('EmsVectorTileLayer', () => { }); }); - describe('isInitialDataLoadComplete', () => { - test('should return false when tile loading has not started', () => { + describe('isLayerLoading', () => { + test('should be true when tile loading has not started', () => { const layer = new EmsVectorTileLayer({ source: {} as unknown as EMSTMSSource, layerDescriptor: {} as unknown as EMSVectorTileLayerDescriptor, }); - expect(layer.isInitialDataLoadComplete()).toBe(false); + expect(layer.isLayerLoading()).toBe(true); }); - test('should return false when tiles are loading', () => { + test('should be true when tiles are loading', () => { const layer = new EmsVectorTileLayer({ source: {} as unknown as EMSTMSSource, layerDescriptor: { __areTilesLoaded: false, } as unknown as EMSVectorTileLayerDescriptor, }); - expect(layer.isInitialDataLoadComplete()).toBe(false); + expect(layer.isLayerLoading()).toBe(true); }); - test('should return true when tiles are loaded', () => { + test('should be false when tiles are loaded', () => { const layer = new EmsVectorTileLayer({ source: {} as unknown as EMSTMSSource, layerDescriptor: { __areTilesLoaded: true, } as unknown as EMSVectorTileLayerDescriptor, }); - expect(layer.isInitialDataLoadComplete()).toBe(true); + expect(layer.isLayerLoading()).toBe(false); }); }); }); diff --git a/x-pack/plugins/maps/public/classes/layers/ems_vector_tile_layer/ems_vector_tile_layer.tsx b/x-pack/plugins/maps/public/classes/layers/ems_vector_tile_layer/ems_vector_tile_layer.tsx index 9188612178003..dac4d628570f0 100644 --- a/x-pack/plugins/maps/public/classes/layers/ems_vector_tile_layer/ems_vector_tile_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/ems_vector_tile_layer/ems_vector_tile_layer.tsx @@ -71,8 +71,9 @@ export class EmsVectorTileLayer extends AbstractLayer { } } - isInitialDataLoadComplete(): boolean { - return !!this._descriptor.__areTilesLoaded; + _isTiled(): boolean { + // Uses tiled maplibre source 'vector' + return true; } getSource(): EMSTMSSource { diff --git a/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.ts b/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.ts index 0d9f11dbe0646..0421fc3b087b5 100644 --- a/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.ts +++ b/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.ts @@ -48,6 +48,11 @@ export class HeatmapLayer extends AbstractLayer { } } + _isTiled(): boolean { + // Uses tiled maplibre source 'vector' + return true; + } + getLayerIcon(isTocIcon: boolean) { const { docCount } = getAggsMeta(this._getMetaFromTiles()); return docCount === 0 ? NO_RESULTS_ICON_AND_TOOLTIPCONTENT : super.getLayerIcon(isTocIcon); diff --git a/x-pack/plugins/maps/public/classes/layers/layer.tsx b/x-pack/plugins/maps/public/classes/layers/layer.tsx index 9e698fee41fa8..cda93f701fe85 100644 --- a/x-pack/plugins/maps/public/classes/layers/layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/layer.tsx @@ -87,7 +87,6 @@ export interface ILayer { ownsMbSourceId(mbSourceId: string): boolean; syncLayerWithMB(mbMap: MbMap, timeslice?: Timeslice): void; getLayerTypeIconName(): string; - isInitialDataLoadComplete(): boolean; getIndexPatternIds(): string[]; getQueryableIndexPatternIds(): string[]; getType(): LAYER_TYPE; @@ -377,11 +376,19 @@ export class AbstractLayer implements ILayer { } isLayerLoading(): boolean { - const areTilesLoading = - typeof this._descriptor.__areTilesLoaded !== 'undefined' - ? !this._descriptor.__areTilesLoaded - : false; - return areTilesLoading || this._dataRequests.some((dataRequest) => dataRequest.isLoading()); + const hasOpenDataRequests = this._dataRequests.some((dataRequest) => dataRequest.isLoading()); + + if (this._isTiled()) { + return ( + hasOpenDataRequests || + this._descriptor.__areTilesLoaded === undefined || + !this._descriptor.__areTilesLoaded + ); + } + + return !this.getSourceDataRequest() + ? true // layer is loading until source data request has been created + : hasOpenDataRequests; } hasErrors(): boolean { @@ -418,11 +425,6 @@ export class AbstractLayer implements ILayer { throw new Error('should implement Layer#getLayerTypeIconName'); } - isInitialDataLoadComplete(): boolean { - const sourceDataRequest = this.getSourceDataRequest(); - return sourceDataRequest ? sourceDataRequest.hasData() : false; - } - async getBounds( getDataRequestContext: (layerId: string) => DataRequestContext ): Promise<MapExtent | null> { @@ -493,4 +495,8 @@ export class AbstractLayer implements ILayer { _getMetaFromTiles(): TileMetaFeature[] { return this._descriptor.__metaFromTiles || []; } + + _isTiled(): boolean { + throw new Error('Must implement AbstractLayer#_isTiled'); + } } diff --git a/x-pack/plugins/maps/public/classes/layers/layer_group/layer_group.tsx b/x-pack/plugins/maps/public/classes/layers/layer_group/layer_group.tsx index 5430ae76e27c4..add3713832813 100644 --- a/x-pack/plugins/maps/public/classes/layers/layer_group/layer_group.tsx +++ b/x-pack/plugins/maps/public/classes/layers/layer_group/layer_group.tsx @@ -330,10 +330,6 @@ export class LayerGroup implements ILayer { return 'layers'; } - isInitialDataLoadComplete(): boolean { - return true; - } - async getBounds( getDataRequestContext: (layerId: string) => DataRequestContext ): Promise<MapExtent | null> { diff --git a/x-pack/plugins/maps/public/classes/layers/raster_tile_layer/raster_tile_layer.ts b/x-pack/plugins/maps/public/classes/layers/raster_tile_layer/raster_tile_layer.ts index cb12d047cbccb..e0666b6b05960 100644 --- a/x-pack/plugins/maps/public/classes/layers/raster_tile_layer/raster_tile_layer.ts +++ b/x-pack/plugins/maps/public/classes/layers/raster_tile_layer/raster_tile_layer.ts @@ -38,6 +38,11 @@ export class RasterTileLayer extends AbstractLayer { this._style = new TileStyle(); } + _isTiled(): boolean { + // Uses tiled maplibre source 'raster' + return true; + } + getSource(): IRasterSource { return super.getSource() as IRasterSource; } diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/geojson_vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/geojson_vector_layer.tsx index 8723de18cd486..419757e24633c 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/geojson_vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/geojson_vector_layer.tsx @@ -60,6 +60,11 @@ export class GeoJsonVectorLayer extends AbstractVectorLayer { return layerDescriptor; } + _isTiled(): boolean { + // Uses untiled maplibre source 'geojson' + return false; + } + async getBounds(getDataRequestContext: (layerId: string) => DataRequestContext) { const isStaticLayer = !this.getSource().isBoundsAware(); return isStaticLayer || this.hasJoins() diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/mvt_vector_layer/mvt_vector_layer.test.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/mvt_vector_layer/mvt_vector_layer.test.tsx index a1d29c8db1363..a976837ee2881 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/mvt_vector_layer/mvt_vector_layer.test.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/mvt_vector_layer/mvt_vector_layer.test.tsx @@ -101,7 +101,7 @@ describe('getFeatureById', () => { }); }); -describe('isInitialDataLoadComplete', () => { +describe('isLayerLoading', () => { const sourceDataRequestDescriptor = { data: {}, dataId: 'source', @@ -109,7 +109,7 @@ describe('isInitialDataLoadComplete', () => { dataRequestMetaAtStart: undefined, dataRequestToken: undefined, }; - test('should return false when tile loading has not started', () => { + test('should be true when tile loading has not started', () => { const layer = new MvtVectorLayer({ customIcons: [], layerDescriptor: { @@ -124,10 +124,10 @@ describe('isInitialDataLoadComplete', () => { }, } as unknown as IVectorSource, }); - expect(layer.isInitialDataLoadComplete()).toBe(false); + expect(layer.isLayerLoading()).toBe(true); }); - test('should return false when tiles are loading', () => { + test('should be true when tiles are loading', () => { const layer = new MvtVectorLayer({ customIcons: [], layerDescriptor: { @@ -143,10 +143,10 @@ describe('isInitialDataLoadComplete', () => { }, } as unknown as IVectorSource, }); - expect(layer.isInitialDataLoadComplete()).toBe(false); + expect(layer.isLayerLoading()).toBe(true); }); - test('should return true when tiles are loaded', () => { + test('should be false when tiles are loaded', () => { const layer = new MvtVectorLayer({ customIcons: [], layerDescriptor: { @@ -162,10 +162,10 @@ describe('isInitialDataLoadComplete', () => { }, } as unknown as IVectorSource, }); - expect(layer.isInitialDataLoadComplete()).toBe(true); + expect(layer.isLayerLoading()).toBe(false); }); - test('should return false when tiles are loaded but join is loading', () => { + test('should be true when tiles are loaded but join is loading', () => { const layer = new MvtVectorLayer({ customIcons: [], joins: [ @@ -198,10 +198,10 @@ describe('isInitialDataLoadComplete', () => { }, } as unknown as IVectorSource, }); - expect(layer.isInitialDataLoadComplete()).toBe(false); + expect(layer.isLayerLoading()).toBe(true); }); - test('should return true when tiles are loaded and joins are loaded', () => { + test('should be false when tiles are loaded and joins are loaded', () => { const layer = new MvtVectorLayer({ customIcons: [], joins: [ @@ -236,6 +236,6 @@ describe('isInitialDataLoadComplete', () => { }, } as unknown as IVectorSource, }); - expect(layer.isInitialDataLoadComplete()).toBe(true); + expect(layer.isLayerLoading()).toBe(false); }); }); diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/mvt_vector_layer/mvt_vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/mvt_vector_layer/mvt_vector_layer.tsx index 398d3daeae28e..4be734ab3be2a 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/mvt_vector_layer/mvt_vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/mvt_vector_layer/mvt_vector_layer.tsx @@ -74,10 +74,9 @@ export class MvtVectorLayer extends AbstractVectorLayer { this._source = args.source as IMvtVectorSource; } - isInitialDataLoadComplete(): boolean { - return this._descriptor.__areTilesLoaded === undefined || !this._descriptor.__areTilesLoaded - ? false - : super.isInitialDataLoadComplete(); + _isTiled(): boolean { + // Uses tiled maplibre source 'vector' + return true; } async getBounds(getDataRequestContext: (layerId: string) => DataRequestContext) { diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx index f8931b4a5755d..dbee11b617dec 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx @@ -270,21 +270,16 @@ export class AbstractVectorLayer extends AbstractLayer implements IVectorLayer { return this.getSource().showJoinEditor(); } - isInitialDataLoadComplete() { - const sourceDataRequest = this.getSourceDataRequest(); - if (!sourceDataRequest || !sourceDataRequest.hasData()) { - return false; - } - - const joins = this.getValidJoins(); - for (let i = 0; i < joins.length; i++) { - const joinDataRequest = this.getDataRequest(joins[i].getSourceDataRequestId()); - if (!joinDataRequest || !joinDataRequest.hasData()) { - return false; - } + isLayerLoading() { + const isSourceLoading = super.isLayerLoading(); + if (isSourceLoading) { + return true; } - return true; + return this.getValidJoins().some((join) => { + const joinDataRequest = this.getDataRequest(join.getSourceDataRequestId()); + return !joinDataRequest || joinDataRequest.isLoading(); + }); } getLayerIcon(isTocIcon: boolean): LayerIcon { diff --git a/x-pack/plugins/maps/public/connected_components/map_container/index.ts b/x-pack/plugins/maps/public/connected_components/map_container/index.ts index f520f9cdc788e..d19c096c36ae9 100644 --- a/x-pack/plugins/maps/public/connected_components/map_container/index.ts +++ b/x-pack/plugins/maps/public/connected_components/map_container/index.ts @@ -16,7 +16,7 @@ import { } from '../../selectors/ui_selectors'; import { cancelAllInFlightRequests, exitFullScreen } from '../../actions'; import { - areLayersLoaded, + isMapLoading, getLayerList, getMapInitError, getMapSettings, @@ -27,7 +27,7 @@ import { MapStoreState } from '../../reducers/store'; function mapStateToProps(state: MapStoreState) { return { isTimesliderOpen: getIsTimesliderOpen(state), - areLayersLoaded: areLayersLoaded(state), + isMapLoading: isMapLoading(state), flyoutDisplay: getFlyoutDisplay(state), isFullScreen: getIsFullScreen(state), mapInitError: getMapInitError(state), diff --git a/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx b/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx index 4e0adbd3d1eb1..e11b1a0530466 100644 --- a/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx +++ b/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx @@ -35,7 +35,7 @@ export interface Props { getFilterActions?: () => Promise<Action[]>; getActionContext?: () => ActionExecutionContext; onSingleValueTrigger?: (actionId: string, key: string, value: RawValue) => void; - areLayersLoaded: boolean; + isMapLoading: boolean; cancelAllInFlightRequests: () => void; exitFullScreen: () => void; flyoutDisplay: FLYOUT_STATE; @@ -86,7 +86,7 @@ export class MapContainer extends Component<Props, State> { this._loadShowTimesliderButton(); if ( this.props.isSharable && - this.props.areLayersLoaded && + !this.props.isMapLoading && !this._isInitalLoadRenderTimerStarted ) { this._isInitalLoadRenderTimerStarted = true; diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/index.ts b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/index.ts index d5dc63ecb8e8b..acfb42b6b38e2 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/index.ts +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/index.ts @@ -24,7 +24,7 @@ import { getIsLayerTOCOpen, getFlyoutDisplay, } from '../../../selectors/ui_selectors'; -import { getLayerList } from '../../../selectors/map_selectors'; +import { getLayerList, getMapZoom } from '../../../selectors/map_selectors'; import { MapStoreState } from '../../../reducers/store'; import { DRAW_MODE } from '../../../../common/constants'; @@ -34,6 +34,7 @@ function mapStateToProps(state: MapStoreState) { isLayerTOCOpen: getIsLayerTOCOpen(state), layerList: getLayerList(state), isFlyoutOpen: getFlyoutDisplay(state) !== FLYOUT_STATE.NONE, + zoom: getMapZoom(state), }; } diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_control.test.tsx b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_control.test.tsx index 1fc9fa6b9755e..c5661adb60eb7 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_control.test.tsx +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_control.test.tsx @@ -33,6 +33,7 @@ const defaultProps = { isLayerTOCOpen: true, layerList: [], isFlyoutOpen: false, + zoom: 0, }; describe('LayerControl', () => { @@ -73,6 +74,9 @@ describe('LayerControl', () => { isVisible: () => { return isVisible; }, + showAtZoomLevel: () => { + return true; + }, } as unknown as ILayer; test('Should render expand button with loading icon when layer is loading', () => { const component = shallow( @@ -105,6 +109,12 @@ describe('LayerControl', () => { isLayerLoading: () => { return false; }, + isVisible: () => { + return true; + }, + showAtZoomLevel: () => { + return true; + }, } as unknown as ILayer; const component = shallow( <LayerControl diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_control.tsx b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_control.tsx index aec1dee70da7b..d8470a9646e1a 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_control.tsx +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_control.tsx @@ -33,6 +33,7 @@ export interface Props { openLayerTOC: () => void; hideAllLayers: () => void; showAllLayers: () => void; + zoom: number; } function renderExpandButton({ @@ -85,6 +86,7 @@ export function LayerControl({ isFlyoutOpen, hideAllLayers, showAllLayers, + zoom, }: Props) { if (!isLayerTOCOpen) { if (isScreenshotMode()) { @@ -94,7 +96,7 @@ export function LayerControl({ return layer.hasErrors(); }); const isLoading = layerList.some((layer) => { - return layer.isLayerLoading() && layer.isVisible(); + return layer.isVisible() && layer.showAtZoomLevel(zoom) && layer.isLayerLoading(); }); return ( diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_button/toc_entry_button.tsx b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_button/toc_entry_button.tsx index eb4bb92b0f338..db4bd5803c216 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_button/toc_entry_button.tsx +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_button/toc_entry_button.tsx @@ -97,14 +97,6 @@ export class TOCEntryButton extends Component<Props, State> { }; } - if (this.props.layer.isLayerLoading()) { - return { - icon: <EuiLoadingSpinner size="m" />, - tooltipContent: '', - footnotes: [], - }; - } - if (!this.props.layer.showAtZoomLevel(this.props.zoom)) { const minZoom = this.props.layer.getMinZoom(); const maxZoom = this.props.layer.getMaxZoom(); @@ -118,6 +110,14 @@ export class TOCEntryButton extends Component<Props, State> { }; } + if (this.props.layer.isLayerLoading()) { + return { + icon: <EuiLoadingSpinner size="m" />, + tooltipContent: '', + footnotes: [], + }; + } + const { icon, tooltipContent } = this.props.layer.getLayerIcon(true); if (isLayerGroup(this.props.layer)) { diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index 3c6eaf77062c3..33552613c0c95 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -58,7 +58,7 @@ import { EventHandlers, } from '../reducers/non_serializable_instances'; import { - areLayersLoaded, + isMapLoading, getGeoFieldNames, getEmbeddableSearchContext, getLayerList, @@ -782,13 +782,8 @@ export class MapEmbeddable }); } - const layers = getLayerList(this._savedMap.getStore().getState()); - const isLoading = - !areLayersLoaded(this._savedMap.getStore().getState()) || - layers.some((layer) => { - return layer.isLayerLoading(); - }); - const firstLayerWithError = layers.find((layer) => { + const isLoading = isMapLoading(this._savedMap.getStore().getState()); + const firstLayerWithError = getLayerList(this._savedMap.getStore().getState()).find((layer) => { return layer.hasErrors(); }); const output = this.getOutput(); diff --git a/x-pack/plugins/maps/public/routes/map_page/map_app/wait_until_time_layers_load.ts b/x-pack/plugins/maps/public/routes/map_page/map_app/wait_until_time_layers_load.ts index 8a9490239a571..bc0eb5867f4a9 100644 --- a/x-pack/plugins/maps/public/routes/map_page/map_app/wait_until_time_layers_load.ts +++ b/x-pack/plugins/maps/public/routes/map_page/map_app/wait_until_time_layers_load.ts @@ -7,7 +7,7 @@ import { from } from 'rxjs'; import { debounceTime, first, map, switchMap } from 'rxjs/operators'; -import { getLayerList } from '../../../selectors/map_selectors'; +import { getLayerList, getMapZoom } from '../../../selectors/map_selectors'; import { MapStore } from '../../../reducers/store'; export function waitUntilTimeLayersLoad$(store: MapStore) { @@ -16,12 +16,17 @@ export function waitUntilTimeLayersLoad$(store: MapStore) { debounceTime(300), // using switchMap since switchMap will discard promise from previous state iterations in progress switchMap(async (state) => { - const promises = getLayerList(state).map(async (layer) => { - return { - isFilteredByGlobalTime: await layer.isFilteredByGlobalTime(), - layer, - }; - }); + const zoom = getMapZoom(state); + const promises = getLayerList(state) + .filter((layer) => { + return layer.isVisible() && layer.showAtZoomLevel(zoom); + }) + .map(async (layer) => { + return { + isFilteredByGlobalTime: await layer.isFilteredByGlobalTime(), + layer, + }; + }); const layersWithMeta = await Promise.all(promises); return layersWithMeta; }), diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.test.ts b/x-pack/plugins/maps/public/selectors/map_selectors.test.ts index fc051d7a48a1e..dd8eb0acd58bc 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.test.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.test.ts @@ -29,7 +29,7 @@ jest.mock('../kibana_services', () => ({ import { DEFAULT_MAP_STORE_STATE } from '../reducers/store'; import { - areLayersLoaded, + isMapLoading, getDataFilters, getTimeFilters, getQueryableUniqueIndexPatternIds, @@ -143,15 +143,15 @@ describe('getTimeFilters', () => { }); }); -describe('areLayersLoaded', () => { +describe('isMapLoading', () => { function createLayerMock({ hasErrors = false, - isInitialDataLoadComplete = false, + isLayerLoading = false, isVisible = true, showAtZoomLevel = true, }: { hasErrors?: boolean; - isInitialDataLoadComplete?: boolean; + isLayerLoading?: boolean; isVisible?: boolean; showAtZoomLevel?: boolean; }) { @@ -159,8 +159,8 @@ describe('areLayersLoaded', () => { hasErrors: () => { return hasErrors; }, - isInitialDataLoadComplete: () => { - return isInitialDataLoadComplete; + isLayerLoading: () => { + return isLayerLoading; }, isVisible: () => { return isVisible; @@ -175,44 +175,42 @@ describe('areLayersLoaded', () => { const layerList: ILayer[] = []; const waitingForMapReadyLayerList: LayerDescriptor[] = [{} as unknown as LayerDescriptor]; const zoom = 4; - expect(areLayersLoaded.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(false); + expect(isMapLoading.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(true); }); test('layer should not be counted as loaded if it has not loaded', () => { - const layerList = [createLayerMock({ isInitialDataLoadComplete: false })]; + const layerList = [createLayerMock({ isLayerLoading: true })]; const waitingForMapReadyLayerList: LayerDescriptor[] = []; const zoom = 4; - expect(areLayersLoaded.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(false); + expect(isMapLoading.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(true); }); test('layer should be counted as loaded if its not visible', () => { - const layerList = [createLayerMock({ isVisible: false, isInitialDataLoadComplete: false })]; + const layerList = [createLayerMock({ isVisible: false, isLayerLoading: true })]; const waitingForMapReadyLayerList: LayerDescriptor[] = []; const zoom = 4; - expect(areLayersLoaded.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(true); + expect(isMapLoading.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(false); }); test('layer should be counted as loaded if its not shown at zoom level', () => { - const layerList = [ - createLayerMock({ showAtZoomLevel: false, isInitialDataLoadComplete: false }), - ]; + const layerList = [createLayerMock({ showAtZoomLevel: false, isLayerLoading: true })]; const waitingForMapReadyLayerList: LayerDescriptor[] = []; const zoom = 4; - expect(areLayersLoaded.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(true); + expect(isMapLoading.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(false); }); test('layer should be counted as loaded if it has a loading error', () => { - const layerList = [createLayerMock({ hasErrors: true, isInitialDataLoadComplete: false })]; + const layerList = [createLayerMock({ hasErrors: true, isLayerLoading: true })]; const waitingForMapReadyLayerList: LayerDescriptor[] = []; const zoom = 4; - expect(areLayersLoaded.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(true); + expect(isMapLoading.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(false); }); test('layer should be counted as loaded if its loaded', () => { - const layerList = [createLayerMock({ isInitialDataLoadComplete: true })]; + const layerList = [createLayerMock({ isLayerLoading: false })]; const waitingForMapReadyLayerList: LayerDescriptor[] = []; const zoom = 4; - expect(areLayersLoaded.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(true); + expect(isMapLoading.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(false); }); }); diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.ts b/x-pack/plugins/maps/public/selectors/map_selectors.ts index 798e24a6141e1..61404d3821952 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.ts @@ -398,11 +398,20 @@ export const hasPreviewLayers = createSelector(getLayerList, (layerList) => { }); }); -export const isLoadingPreviewLayers = createSelector(getLayerList, (layerList) => { - return layerList.some((layer) => { - return layer.isPreviewLayer() && layer.isLayerLoading(); - }); -}); +export const isLoadingPreviewLayers = createSelector( + getLayerList, + getMapZoom, + (layerList, zoom) => { + return layerList.some((layer) => { + return ( + layer.isPreviewLayer() && + layer.isVisible() && + layer.showAtZoomLevel(zoom) && + layer.isLayerLoading() + ); + }); + } +); export const getMapColors = createSelector(getLayerListRaw, (layerList) => layerList @@ -488,13 +497,13 @@ export const hasDirtyState = createSelector(getLayerListRaw, (layerListRaw) => { }); }); -export const areLayersLoaded = createSelector( +export const isMapLoading = createSelector( getLayerList, getWaitingForMapReadyLayerListRaw, getMapZoom, (layerList, waitingForMapReadyLayerList, zoom) => { if (waitingForMapReadyLayerList.length) { - return false; + return true; } for (let i = 0; i < layerList.length; i++) { @@ -503,11 +512,11 @@ export const areLayersLoaded = createSelector( layer.isVisible() && layer.showAtZoomLevel(zoom) && !layer.hasErrors() && - !layer.isInitialDataLoadComplete() + layer.isLayerLoading() ) { - return false; + return true; } } - return true; + return false; } ); From 682e2ed6aee8bef8127cfa1cba44dff2eb681c31 Mon Sep 17 00:00:00 2001 From: "Quynh Nguyen (Quinn)" <43350163+qn895@users.noreply.github.com> Date: Tue, 11 Apr 2023 15:52:08 -0500 Subject: [PATCH 16/23] [ML] Add execution context to Field statistic table for Discover and Index data visualizer (#154404) Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../common/types/field_stats.ts | 9 ++++--- .../index_data_visualizer_view.tsx | 1 + .../hooks/use_data_visualizer_grid_data.ts | 26 ++++++++++++++++++- .../hooks/use_field_stats.ts | 5 +++- .../hooks/use_overall_stats.ts | 5 +++- x-pack/plugins/data_visualizer/tsconfig.json | 1 + 6 files changed, 41 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/data_visualizer/common/types/field_stats.ts b/x-pack/plugins/data_visualizer/common/types/field_stats.ts index 5f825c5299115..5fef7b4ae8f77 100644 --- a/x-pack/plugins/data_visualizer/common/types/field_stats.ts +++ b/x-pack/plugins/data_visualizer/common/types/field_stats.ts @@ -6,10 +6,11 @@ */ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { Query } from '@kbn/es-query'; -import { IKibanaSearchResponse } from '@kbn/data-plugin/common'; +import type { Query } from '@kbn/es-query'; +import type { IKibanaSearchResponse } from '@kbn/data-plugin/common'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; -import { TimeBucketsInterval } from '../services/time_buckets'; +import type { KibanaExecutionContext } from '@kbn/core-execution-context-common'; +import type { TimeBucketsInterval } from '../services/time_buckets'; export interface RandomSamplingOption { mode: 'random_sampling'; @@ -209,6 +210,7 @@ export interface FieldStatsCommonRequestParams { samplingProbability: number | null; browserSessionSeed: number; samplingOption: SamplingOption; + embeddableExecutionContext?: KibanaExecutionContext; } export type SupportedAggs = Set<string>; @@ -232,6 +234,7 @@ export interface OverallStatsSearchStrategyParams { fieldsToFetch?: string[]; browserSessionSeed: number; samplingOption: SamplingOption; + embeddableExecutionContext?: KibanaExecutionContext; } export interface FieldStatsSearchStrategyReturnBase { diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx index 8ea4794ee548f..6d763b7fbbb93 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx @@ -277,6 +277,7 @@ export const IndexDataVisualizerView: FC<IndexDataVisualizerViewProps> = (dataVi sessionId: currentSessionId, visibleFieldNames, allowEditDataView: true, + id: 'index_data_visualizer', }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [currentDataView.id, currentSavedSearch?.id, visibleFieldNames, currentSessionId]); diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_data_visualizer_grid_data.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_data_visualizer_grid_data.ts index 224cbd5208b8e..b948cab5ee1ed 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_data_visualizer_grid_data.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_data_visualizer_grid_data.ts @@ -16,6 +16,10 @@ import seedrandom from 'seedrandom'; import type { SamplingOption } from '@kbn/discover-plugin/public/application/main/components/field_stats_table/field_stats_table'; import type { Dictionary } from '@kbn/ml-url-state'; import { mlTimefilterRefresh$, useTimefilter } from '@kbn/ml-date-picker'; +import useObservable from 'react-use/lib/useObservable'; +import type { KibanaExecutionContext } from '@kbn/core-execution-context-common'; +import { useExecutionContext } from '@kbn/kibana-react-plugin/public'; +import { DATA_VISUALIZER_GRID_EMBEDDABLE_TYPE } from '../embeddables/grid_embeddable/constants'; import { filterFields } from '../../common/components/fields_stats_grid/filter_fields'; import type { RandomSamplerOption } from '../constants/random_sampler'; import type { DataVisualizerIndexBasedAppState } from '../types/index_data_visualizer_state'; @@ -58,7 +62,25 @@ export const useDataVisualizerGridData = ( onUpdate?: (params: Dictionary<unknown>) => void ) => { const { services } = useDataVisualizerKibana(); - const { uiSettings, data, security } = services; + const { uiSettings, data, security, executionContext } = services; + + const parentExecutionContext = useObservable(executionContext?.context$); + + const embeddableExecutionContext: KibanaExecutionContext = useMemo(() => { + const child: KibanaExecutionContext = { + type: 'visualization', + name: DATA_VISUALIZER_GRID_EMBEDDABLE_TYPE, + id: input.id, + }; + + return { + ...(parentExecutionContext ? parentExecutionContext : {}), + child, + }; + }, [parentExecutionContext, input.id]); + + useExecutionContext(executionContext, embeddableExecutionContext); + const { samplerShardSize, visibleFieldTypes, showEmptyFields } = dataVisualizerListState; const [lastRefresh, setLastRefresh] = useState(0); @@ -236,6 +258,7 @@ export const useDataVisualizerGridData = ( fieldsToFetch, browserSessionSeed, samplingOption: { ...samplingOption, seed: browserSessionSeed.toString() }, + embeddableExecutionContext, }; }, // eslint-disable-next-line react-hooks/exhaustive-deps @@ -252,6 +275,7 @@ export const useDataVisualizerGridData = ( lastRefresh, fieldsToFetch, browserSessionSeed, + embeddableExecutionContext, ] ); diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_field_stats.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_field_stats.ts index d04106c2b0932..f47bd9aebb33d 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_field_stats.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_field_stats.ts @@ -170,9 +170,12 @@ export function useFieldStatsSearchStrategy( browserSessionSeed: searchStrategyParams.browserSessionSeed, samplingOption: searchStrategyParams.samplingOption, }; + + const { sessionId, embeddableExecutionContext } = searchStrategyParams; const searchOptions: ISearchOptions = { abortSignal: abortCtrl.current.signal, - sessionId: searchStrategyParams?.sessionId, + sessionId, + ...(embeddableExecutionContext ? { executionContext: embeddableExecutionContext } : {}), }; const batches = createBatchedRequests( diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_overall_stats.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_overall_stats.ts index a3bf2b7b0cd64..ced7bf1058762 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_overall_stats.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_overall_stats.ts @@ -137,11 +137,14 @@ export function useOverallStats<TParams extends OverallStatsSearchStrategyParams latest, runtimeFieldMap, samplingOption, + sessionId, + embeddableExecutionContext, } = searchStrategyParams; const searchOptions: ISearchOptions = { abortSignal: abortCtrl.current.signal, - sessionId: searchStrategyParams?.sessionId, + sessionId, + ...(embeddableExecutionContext ? { executionContext: embeddableExecutionContext } : {}), }; const documentCountStats = await getDocumentCountStats( diff --git a/x-pack/plugins/data_visualizer/tsconfig.json b/x-pack/plugins/data_visualizer/tsconfig.json index 3e9956d828a27..f87aef45463c1 100644 --- a/x-pack/plugins/data_visualizer/tsconfig.json +++ b/x-pack/plugins/data_visualizer/tsconfig.json @@ -58,6 +58,7 @@ "@kbn/ml-query-utils", "@kbn/saved-search-plugin", "@kbn/unified-field-list-plugin", + "@kbn/core-execution-context-common", ], "exclude": [ "target/**/*", From 2f469298054fdc2897c33953c0ba01a24446933e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Tue, 11 Apr 2023 20:35:18 -0400 Subject: [PATCH 17/23] [Profiling] updating empty state page links. (#154678) --- .../public/components/check_setup.tsx | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/profiling/public/components/check_setup.tsx b/x-pack/plugins/profiling/public/components/check_setup.tsx index bbfd4a35a9dfc..f7eedc2e210fd 100644 --- a/x-pack/plugins/profiling/public/components/check_setup.tsx +++ b/x-pack/plugins/profiling/public/components/check_setup.tsx @@ -15,6 +15,7 @@ import { EuiText, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; import React, { useState } from 'react'; import { AsyncStatus, useAsync } from '../hooks/use_async'; import { useAutoAbortedHttpClient } from '../hooks/use_auto_aborted_http_client'; @@ -28,6 +29,8 @@ export function CheckSetup({ children }: { children: React.ReactElement }) { services: { fetchHasSetup, postSetupResources }, } = useProfilingDependencies(); + const { docLinks, notifications } = core; + const [postSetupLoading, setPostSetupLoading] = useState(false); const { status, data, error, refresh } = useAsync( @@ -47,8 +50,6 @@ export function CheckSetup({ children }: { children: React.ReactElement }) { const displayUi = data?.has_data === true; - const docsLink = `https://elastic.github.io/universal-profiling-documentation`; - const displayLoadingScreen = status !== AsyncStatus.Settled; if (displayLoadingScreen) { @@ -89,7 +90,7 @@ export function CheckSetup({ children }: { children: React.ReactElement }) { <ProfilingAppPageTemplate tabs={[]} noDataConfig={{ - docsLink, + docsLink: `${docLinks.ELASTIC_WEBSITE_URL}/guide/en/observability/${docLinks.DOC_LINK_VERSION}/profiling-get-started.html`, logo: 'logoObservability', pageTitle: i18n.translate('xpack.profiling.noDataConfig.pageTitle', { defaultMessage: 'Universal Profiling (now in Beta)', @@ -118,15 +119,23 @@ export function CheckSetup({ children }: { children: React.ReactElement }) { <EuiText size={'xs'}> <ul> <li> - {i18n.translate('xpack.profiling.noDataConfig.action.dataRetention', { - defaultMessage: `Normal data storage costs apply for profiling data stored in Elasticsearch. - To control data retention. `, - })} - <EuiLink target="_blank" href={docsLink}> - {i18n.translate('xpack.profiling.noDataConfig.readMore.linkLabel', { - defaultMessage: 'Read more', - })} - </EuiLink> + <FormattedMessage + id="xpack.profiling.noDataConfig.action.dataRetention" + defaultMessage="Normal data storage costs apply for profiling data stored in Elasticsearch. Learn more about {dataRetentionLink}." + values={{ + dataRetentionLink: ( + <EuiLink + href={`${docLinks.ELASTIC_WEBSITE_URL}/guide/en/elasticsearch/reference/${docLinks.DOC_LINK_VERSION}/set-up-lifecycle-policy.html`} + target="_blank" + > + {i18n.translate( + 'xpack.profiling.noDataConfig.action.dataRetention.link', + { defaultMessage: 'controlling data retention' } + )} + </EuiLink> + ), + }} + /> </li> <li> {i18n.translate('xpack.profiling.noDataConfig.action.legalBetaTerms', { @@ -162,7 +171,7 @@ export function CheckSetup({ children }: { children: React.ReactElement }) { .catch((err) => { const message = err?.body?.message ?? err.message ?? String(err); - core.notifications.toasts.addError(err, { + notifications.toasts.addError(err, { title: i18n.translate( 'xpack.profiling.checkSetup.setupFailureToastTitle', { defaultMessage: 'Failed to complete setup' } From 2f001a2f8d2ba9ab780bb2023229bd3bbf32dff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Tue, 11 Apr 2023 20:35:48 -0400 Subject: [PATCH 18/23] [Profiling] Space-specific feature privileges (#154734) --- x-pack/plugins/profiling/public/plugin.tsx | 45 ++++++++++++---------- x-pack/plugins/profiling/server/feature.ts | 14 +++---- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/x-pack/plugins/profiling/public/plugin.tsx b/x-pack/plugins/profiling/public/plugin.tsx index 4875af624fb9b..ae3030b528efb 100644 --- a/x-pack/plugins/profiling/public/plugin.tsx +++ b/x-pack/plugins/profiling/public/plugin.tsx @@ -50,27 +50,30 @@ export class ProfilingPlugin implements Plugin { const kuerySubject = new BehaviorSubject<string>(''); const section$ = combineLatest([from(coreSetup.getStartServices()), kuerySubject]).pipe( - map(([_, kuery]) => { - const sections: NavigationSection[] = [ - { - label: i18n.translate('xpack.profiling.navigation.sectionLabel', { - defaultMessage: 'Universal Profiling', - }), - isBetaFeature: true, - entries: links.map((link) => { - return { - app: 'profiling', - label: link.title, - path: `${link.path}?kuery=${kuery ?? ''}`, - matchPath: (path) => { - return path.startsWith(link.path); - }, - }; - }), - sortKey: 700, - }, - ]; - return sections; + map(([[coreStart], kuery]) => { + if (coreStart.application.capabilities.profiling.show) { + const sections: NavigationSection[] = [ + { + label: i18n.translate('xpack.profiling.navigation.sectionLabel', { + defaultMessage: 'Universal Profiling', + }), + isBetaFeature: true, + entries: links.map((link) => { + return { + app: 'profiling', + label: link.title, + path: `${link.path}?kuery=${kuery ?? ''}`, + matchPath: (path) => { + return path.startsWith(link.path); + }, + }; + }), + sortKey: 700, + }, + ]; + return sections; + } + return []; }) ); diff --git a/x-pack/plugins/profiling/server/feature.ts b/x-pack/plugins/profiling/server/feature.ts index e6d9c3098dc03..ec382952363df 100644 --- a/x-pack/plugins/profiling/server/feature.ts +++ b/x-pack/plugins/profiling/server/feature.ts @@ -17,13 +17,13 @@ export const PROFILING_FEATURE = { }), order: 1200, category: DEFAULT_APP_CATEGORIES.observability, - app: ['kibana'], - catalogue: [], + app: [PROFILING_SERVER_FEATURE_ID, 'ux', 'kibana'], + catalogue: [PROFILING_SERVER_FEATURE_ID], // see x-pack/plugins/features/common/feature_kibana_privileges.ts privileges: { all: { - app: ['kibana'], - catalogue: [], + app: [PROFILING_SERVER_FEATURE_ID, 'ux', 'kibana'], + catalogue: [PROFILING_SERVER_FEATURE_ID], savedObject: { all: [], read: [], @@ -31,13 +31,13 @@ export const PROFILING_FEATURE = { ui: ['show'], }, read: { - app: ['kibana'], - catalogue: [], + app: [PROFILING_SERVER_FEATURE_ID, 'ux', 'kibana'], + catalogue: [PROFILING_SERVER_FEATURE_ID], savedObject: { all: [], read: [], }, - ui: [], + ui: ['show'], }, }, }; From f111d93d089d881c3ca03731541517b8ab29d0ae Mon Sep 17 00:00:00 2001 From: Jonathan Buttner <56361221+jonathan-buttner@users.noreply.github.com> Date: Tue, 11 Apr 2023 22:15:26 -0400 Subject: [PATCH 19/23] [Cases] Adding cases settings docs (#154672) This PR adds the new configuration settings to the docs. The configurations were added in this PR: https://github.com/elastic/kibana/pull/154013 --------- Co-authored-by: lcawl <lcawley@elastic.co> --- docs/management/cases/cases.asciidoc | 3 ++- docs/settings/cases-settings.asciidoc | 15 +++++++++++++++ docs/setup/settings.asciidoc | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 docs/settings/cases-settings.asciidoc diff --git a/docs/management/cases/cases.asciidoc b/docs/management/cases/cases.asciidoc index dc72b453f5e94..7d32ddc527930 100644 --- a/docs/management/cases/cases.asciidoc +++ b/docs/management/cases/cases.asciidoc @@ -20,4 +20,5 @@ cases in *{stack-manage-app}*. * <<setup-cases>> * <<manage-cases>> -* <<add-case-connectors>> \ No newline at end of file +* <<add-case-connectors>> +* <<cases-settings>> \ No newline at end of file diff --git a/docs/settings/cases-settings.asciidoc b/docs/settings/cases-settings.asciidoc new file mode 100644 index 0000000000000..4923e043f8d2b --- /dev/null +++ b/docs/settings/cases-settings.asciidoc @@ -0,0 +1,15 @@ +[[cases-settings]] +== Cases settings in {kib} +++++ +<titleabbrev>Cases settings</titleabbrev> +++++ + +You do not need to configure any additional settings to use <<cases,cases>> in {kib}. +To provide greater control over case features, you can configure the following settings in the `kibana.yml` file: + +`xpack.cases.files.allowedMimeTypes`:: +The MIME types that you can attach to a case, represented in an array of strings. For example: `['image/tiff','text/csv','application/zip'].` +The default MIME types are specified in https://github.com/elastic/kibana/blob/{branch}/x-pack/plugins/cases/common/constants/mime_types.ts[mime_types.ts]. + +`xpack.cases.files.maxSize`:: +The size limit for files that you can attach to a case, represented as the number of bytes. By default, the limit is 10 MiB for images and 100 MiB for all other MIME types. If you specify a value for this setting, it affects all file types. diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 3c45338c4da90..ca8eaf10583af 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -622,6 +622,7 @@ Valid locales are: `en`, `zh-CN`, `ja-JP`. *Default: `en`* include::{kib-repo-dir}/settings/alert-action-settings.asciidoc[] include::{kib-repo-dir}/settings/apm-settings.asciidoc[] include::{kib-repo-dir}/settings/banners-settings.asciidoc[] +include::{kib-repo-dir}/settings/cases-settings.asciidoc[leveloffset=+1] include::{kib-repo-dir}/settings/enterprise-search-settings.asciidoc[] include::{kib-repo-dir}/settings/fleet-settings.asciidoc[] include::{kib-repo-dir}/settings/i18n-settings.asciidoc[] From 6365d54d062c45c2f49f9dee400bd83e79b2ea11 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 12 Apr 2023 00:48:12 -0400 Subject: [PATCH 20/23] [api-docs] 2023-04-12 Daily api_docs build (#154794) Generated by https://buildkite.com/elastic/kibana-api-docs-daily/builds/305 --- api_docs/actions.mdx | 2 +- api_docs/advanced_settings.mdx | 2 +- api_docs/aiops.mdx | 2 +- api_docs/alerting.devdocs.json | 67 ++- api_docs/alerting.mdx | 4 +- api_docs/apm.devdocs.json | 41 +- api_docs/apm.mdx | 4 +- api_docs/asset_manager.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_chat.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.devdocs.json | 32 - api_docs/data.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.devdocs.json | 16 - api_docs/data_views.mdx | 2 +- api_docs/data_visualizer.mdx | 2 +- api_docs/deprecations_by_api.mdx | 14 +- api_docs/deprecations_by_plugin.mdx | 28 +- api_docs/deprecations_by_team.mdx | 2 +- api_docs/dev_tools.mdx | 2 +- api_docs/discover.devdocs.json | 4 - api_docs/discover.mdx | 2 +- api_docs/discover_enhanced.mdx | 2 +- api_docs/ecs_data_quality_dashboard.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/event_annotation.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/file_upload.mdx | 2 +- api_docs/files.mdx | 2 +- api_docs/files_management.mdx | 2 +- api_docs/fleet.mdx | 2 +- 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/inspector.mdx | 2 +- api_docs/interactive_setup.mdx | 2 +- api_docs/kbn_ace.mdx | 2 +- api_docs/kbn_aiops_components.devdocs.json | 8 +- api_docs/kbn_aiops_components.mdx | 2 +- api_docs/kbn_aiops_utils.mdx | 2 +- api_docs/kbn_alerting_state_types.mdx | 2 +- api_docs/kbn_alerts.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 +- ..._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_analytics_shippers_gainsight.mdx | 2 +- api_docs/kbn_apm_config_loader.mdx | 2 +- api_docs/kbn_apm_synthtrace.mdx | 2 +- .../kbn_apm_synthtrace_client.devdocs.json | 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_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_mocks.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 +- .../kbn_content_management_table_list.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 +- .../kbn_core_lifecycle_browser.devdocs.json | 28 - 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 +- 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 +- ...ore_saved_objects_api_browser.devdocs.json | 80 --- .../kbn_core_saved_objects_api_browser.mdx | 2 +- .../kbn_core_saved_objects_api_server.mdx | 2 +- ...core_saved_objects_api_server_internal.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 +- ...kbn_core_saved_objects_common.devdocs.json | 20 +- 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_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 +- ...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_internal.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_crypto.mdx | 2 +- api_docs/kbn_crypto_browser.mdx | 2 +- api_docs/kbn_cypress_config.mdx | 2 +- api_docs/kbn_datemath.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_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.mdx | 2 +- api_docs/kbn_ecs_data_quality_dashboard.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_expandable_flyout.mdx | 2 +- api_docs/kbn_field_types.mdx | 2 +- api_docs/kbn_find_used_node_modules.mdx | 2 +- .../kbn_ftr_common_functional_services.mdx | 2 +- api_docs/kbn_generate.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_interpreter.mdx | 2 +- api_docs/kbn_io_ts_utils.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_logging.mdx | 2 +- api_docs/kbn_logging_mocks.mdx | 2 +- api_docs/kbn_managed_vscode_config.mdx | 2 +- api_docs/kbn_mapbox_gl.mdx | 2 +- api_docs/kbn_ml_agg_utils.devdocs.json | 78 +-- api_docs/kbn_ml_agg_utils.mdx | 4 +- api_docs/kbn_ml_date_picker.mdx | 2 +- api_docs/kbn_ml_is_defined.mdx | 2 +- api_docs/kbn_ml_is_populated_object.mdx | 2 +- api_docs/kbn_ml_local_storage.mdx | 2 +- api_docs/kbn_ml_nested_property.mdx | 2 +- api_docs/kbn_ml_query_utils.mdx | 2 +- .../kbn_ml_random_sampler_utils.devdocs.json | 136 +++++ api_docs/kbn_ml_random_sampler_utils.mdx | 33 + api_docs/kbn_ml_route_utils.mdx | 2 +- api_docs/kbn_ml_string_hash.mdx | 2 +- api_docs/kbn_ml_trained_models_utils.mdx | 2 +- api_docs/kbn_ml_url_state.mdx | 2 +- api_docs/kbn_monaco.mdx | 2 +- api_docs/kbn_object_versioning.mdx | 2 +- api_docs/kbn_observability_alert_details.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 +- ..._performance_testing_dataset_extractor.mdx | 2 +- api_docs/kbn_plugin_generator.mdx | 2 +- api_docs/kbn_plugin_helpers.mdx | 2 +- api_docs/kbn_react_field.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_rison.mdx | 2 +- api_docs/kbn_rule_data_utils.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_ecs.mdx | 2 +- api_docs/kbn_securitysolution_es_utils.mdx | 2 +- ...ritysolution_exception_list_components.mdx | 2 +- api_docs/kbn_securitysolution_grouping.mdx | 2 +- api_docs/kbn_securitysolution_hook_utils.mdx | 2 +- ...solution_io_ts_alerting_types.devdocs.json | 314 +++++++++- ..._securitysolution_io_ts_alerting_types.mdx | 4 +- .../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_shared_svg.mdx | 2 +- api_docs/kbn_shared_ux_avatar_solution.mdx | 2 +- ...ared_ux_avatar_user_profile_components.mdx | 2 +- .../kbn_shared_ux_button_exit_full_screen.mdx | 2 +- ...hared_ux_button_exit_full_screen_mocks.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_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_utility.mdx | 2 +- api_docs/kbn_slo_schema.devdocs.json | 110 +--- api_docs/kbn_slo_schema.mdx | 2 +- api_docs/kbn_some_dev_log.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_jest_helpers.mdx | 2 +- api_docs/kbn_test_subj_selector.mdx | 2 +- api_docs/kbn_tooling_log.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_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_yarn_lock_validator.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/lists.mdx | 2 +- api_docs/management.mdx | 2 +- api_docs/maps.mdx | 2 +- api_docs/maps_ems.mdx | 2 +- api_docs/ml.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/notifications.mdx | 2 +- api_docs/observability.devdocs.json | 52 +- api_docs/observability.mdx | 2 +- api_docs/observability_shared.devdocs.json | 565 ++++++++++++++++++ api_docs/observability_shared.mdx | 41 ++ api_docs/osquery.mdx | 2 +- api_docs/plugin_directory.mdx | 18 +- api_docs/presentation_util.mdx | 2 +- api_docs/profiling.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/security.mdx | 2 +- api_docs/security_solution.mdx | 2 +- api_docs/session_view.mdx | 2 +- api_docs/share.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/threat_intelligence.mdx | 2 +- api_docs/timelines.mdx | 2 +- api_docs/transform.mdx | 2 +- api_docs/triggers_actions_ui.devdocs.json | 2 +- api_docs/triggers_actions_ui.mdx | 2 +- api_docs/ui_actions.mdx | 2 +- api_docs/ui_actions_enhanced.mdx | 2 +- api_docs/unified_field_list.mdx | 2 +- api_docs/unified_histogram.mdx | 2 +- api_docs/unified_search.devdocs.json | 74 ++- api_docs/unified_search.mdx | 4 +- api_docs/unified_search_autocomplete.mdx | 4 +- 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 +- 511 files changed, 1863 insertions(+), 888 deletions(-) create mode 100644 api_docs/kbn_ml_random_sampler_utils.devdocs.json create mode 100644 api_docs/kbn_ml_random_sampler_utils.mdx create mode 100644 api_docs/observability_shared.devdocs.json create mode 100644 api_docs/observability_shared.mdx diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 177ce0dce6055..6ff5655ccf5f8 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: 2023-04-11 +date: 2023-04-12 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 b7a01f7393f1b..64f62734ad1d7 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index 895af7c8acd15..896436f5d9931 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.devdocs.json b/api_docs/alerting.devdocs.json index fa8e148dc183b..adf1582e2734c 100644 --- a/api_docs/alerting.devdocs.json +++ b/api_docs/alerting.devdocs.json @@ -5301,7 +5301,14 @@ "label": "days", "description": [], "signature": [ - "(2 | 7 | 6 | 5 | 4 | 3 | 1)[]" + { + "pluginId": "alerting", + "scope": "common", + "docId": "kibAlertingPluginApi", + "section": "def-common.IsoWeekday", + "text": "IsoWeekday" + }, + "[]" ], "path": "x-pack/plugins/alerting/common/rule.ts", "deprecated": false, @@ -6879,6 +6886,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "alerting", + "id": "def-common.Rule.apiKeyCreatedByUser", + "type": "CompoundType", + "tags": [], + "label": "apiKeyCreatedByUser", + "description": [], + "signature": [ + "boolean | null | undefined" + ], + "path": "x-pack/plugins/alerting/common/rule.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "alerting", "id": "def-common.Rule.throttle", @@ -8818,6 +8839,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "alerting", + "id": "def-common.IsoWeekday", + "type": "Type", + "tags": [], + "label": "IsoWeekday", + "description": [], + "signature": [ + "2 | 7 | 6 | 5 | 4 | 3 | 1" + ], + "path": "x-pack/plugins/alerting/common/rule.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "alerting", "id": "def-common.LastScheduledActions", @@ -9051,6 +9087,35 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "alerting", + "id": "def-common.RuleActionAlertsFilterProperty", + "type": "Type", + "tags": [], + "label": "RuleActionAlertsFilterProperty", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectAttribute", + "text": "SavedObjectAttribute" + }, + " | ", + { + "pluginId": "alerting", + "scope": "common", + "docId": "kibAlertingPluginApi", + "section": "def-common.AlertsFilterTimeframe", + "text": "AlertsFilterTimeframe" + } + ], + "path": "x-pack/plugins/alerting/common/rule.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "alerting", "id": "def-common.RuleActionParam", diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index f209e98f957a1..47e096a70ae6e 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 564 | 1 | 543 | 41 | +| 567 | 1 | 546 | 41 | ## Client diff --git a/api_docs/apm.devdocs.json b/api_docs/apm.devdocs.json index fdff221d15c4a..68e7c2735ea9f 100644 --- a/api_docs/apm.devdocs.json +++ b/api_docs/apm.devdocs.json @@ -39,6 +39,17 @@ "path": "x-pack/plugins/apm/public/index.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "apm", + "id": "def-public.ConfigSchema.latestAgentVersionsUrl", + "type": "string", + "tags": [], + "label": "latestAgentVersionsUrl", + "description": [], + "path": "x-pack/plugins/apm/public/index.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -204,7 +215,7 @@ "Observable", "<Readonly<{} & { indices: Readonly<{} & { error: string; metric: string; span: string; transaction: string; onboarding: string; }>; autoCreateApmDataView: boolean; serviceMapEnabled: boolean; serviceMapFingerprintBucketSize: number; serviceMapFingerprintGlobalBucketSize: number; serviceMapTraceIdBucketSize: number; serviceMapTraceIdGlobalBucketSize: number; serviceMapMaxTracesPerRequest: number; ui: Readonly<{} & { enabled: boolean; maxTraceItems: number; }>; searchAggregatedTransactions: ", "SearchAggregatedTransactionSetting", - "; telemetryCollectionEnabled: boolean; metricsInterval: number; agent: Readonly<{} & { migrations: Readonly<{} & { enabled: boolean; }>; }>; forceSyntheticSource: boolean; }>>; getApmIndices: () => Promise<Readonly<{ error: string; onboarding: string; span: string; transaction: string; metric: string; }>>; createApmEventClient: ({ request, context, debug, }: { debug?: boolean | undefined; request: ", + "; telemetryCollectionEnabled: boolean; metricsInterval: number; agent: Readonly<{} & { migrations: Readonly<{} & { enabled: boolean; }>; }>; forceSyntheticSource: boolean; latestAgentVersionsUrl: string; }>>; getApmIndices: () => Promise<Readonly<{ error: string; onboarding: string; span: string; transaction: string; metric: string; }>>; createApmEventClient: ({ request, context, debug, }: { debug?: boolean | undefined; request: ", { "pluginId": "@kbn/core-http-server", "scope": "common", @@ -450,7 +461,7 @@ "signature": [ "{ readonly indices: Readonly<{} & { error: string; metric: string; span: string; transaction: string; onboarding: string; }>; readonly autoCreateApmDataView: boolean; readonly serviceMapEnabled: boolean; readonly serviceMapFingerprintBucketSize: number; readonly serviceMapFingerprintGlobalBucketSize: number; readonly serviceMapTraceIdBucketSize: number; readonly serviceMapTraceIdGlobalBucketSize: number; readonly serviceMapMaxTracesPerRequest: number; readonly ui: Readonly<{} & { enabled: boolean; maxTraceItems: number; }>; readonly searchAggregatedTransactions: ", "SearchAggregatedTransactionSetting", - "; readonly telemetryCollectionEnabled: boolean; readonly metricsInterval: number; readonly agent: Readonly<{} & { migrations: Readonly<{} & { enabled: boolean; }>; }>; readonly forceSyntheticSource: boolean; }" + "; readonly telemetryCollectionEnabled: boolean; readonly metricsInterval: number; readonly agent: Readonly<{} & { migrations: Readonly<{} & { enabled: boolean; }>; }>; readonly forceSyntheticSource: boolean; readonly latestAgentVersionsUrl: string; }" ], "path": "x-pack/plugins/apm/server/routes/typings.ts", "deprecated": false, @@ -810,7 +821,7 @@ "label": "APIEndpoint", "description": [], "signature": [ - "\"POST /internal/apm/data_view/static\" | \"GET /internal/apm/data_view/title\" | \"GET /internal/apm/environments\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics_by_transaction_name\" | \"POST /internal/apm/services/{serviceName}/errors/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/samples\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/error/{errorId}\" | \"GET /internal/apm/services/{serviceName}/errors/distribution\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/top_erroneous_transactions\" | \"POST /internal/apm/latency/overall_distribution/transactions\" | \"GET /internal/apm/services/{serviceName}/metrics/charts\" | \"GET /internal/apm/services/{serviceName}/metrics/nodes\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/charts\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/summary\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/functions_overview\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/active_instances\" | \"GET /internal/apm/observability_overview\" | \"GET /internal/apm/observability_overview/has_data\" | \"GET /internal/apm/service-map\" | \"GET /internal/apm/service-map/service/{serviceName}\" | \"GET /internal/apm/service-map/dependency\" | \"GET /internal/apm/services\" | \"POST /internal/apm/services/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/metadata/details\" | \"GET /internal/apm/services/{serviceName}/metadata/icons\" | \"GET /internal/apm/services/{serviceName}/agent\" | \"GET /internal/apm/services/{serviceName}/transaction_types\" | \"GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata\" | \"GET /api/apm/services/{serviceName}/annotation/search\" | \"POST /api/apm/services/{serviceName}/annotation\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\" | \"GET /internal/apm/services/{serviceName}/throughput\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/dependencies\" | \"GET /internal/apm/services/{serviceName}/dependencies/breakdown\" | \"GET /internal/apm/services/{serviceName}/anomaly_charts\" | \"GET /internal/apm/services/{serviceName}/alerts_count\" | \"GET /internal/apm/service-groups\" | \"GET /internal/apm/service-group\" | \"POST /internal/apm/service-group\" | \"DELETE /internal/apm/service-group\" | \"GET /internal/apm/service-group/services\" | \"GET /internal/apm/service-group/counts\" | \"GET /internal/apm/suggestions\" | \"GET /internal/apm/traces/{traceId}\" | \"GET /internal/apm/traces\" | \"GET /internal/apm/traces/{traceId}/root_transaction\" | \"GET /internal/apm/transactions/{transactionId}\" | \"GET /internal/apm/traces/find\" | \"POST /internal/apm/traces/aggregated_critical_path\" | \"GET /internal/apm/traces/{traceId}/transactions/{transactionId}\" | \"GET /internal/apm/traces/{traceId}/spans/{spanId}\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/latency\" | \"GET /internal/apm/services/{serviceName}/transactions/traces/samples\" | \"GET /internal/apm/services/{serviceName}/transaction/charts/breakdown\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/error_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate_by_transaction_name\" | \"GET /internal/apm/rule_types/transaction_error_rate/chart_preview\" | \"GET /internal/apm/rule_types/transaction_duration/chart_preview\" | \"GET /internal/apm/rule_types/error_count/chart_preview\" | \"GET /api/apm/settings/agent-configuration\" | \"GET /api/apm/settings/agent-configuration/view\" | \"DELETE /api/apm/settings/agent-configuration\" | \"PUT /api/apm/settings/agent-configuration\" | \"POST /api/apm/settings/agent-configuration/search\" | \"GET /api/apm/settings/agent-configuration/environments\" | \"GET /api/apm/settings/agent-configuration/agent_name\" | \"GET /internal/apm/settings/anomaly-detection/jobs\" | \"POST /internal/apm/settings/anomaly-detection/jobs\" | \"GET /internal/apm/settings/anomaly-detection/environments\" | \"POST /internal/apm/settings/anomaly-detection/update_to_v3\" | \"GET /internal/apm/settings/apm-index-settings\" | \"GET /internal/apm/settings/apm-indices\" | \"POST /internal/apm/settings/apm-indices/save\" | \"GET /internal/apm/settings/custom_links/transaction\" | \"GET /internal/apm/settings/custom_links\" | \"POST /internal/apm/settings/custom_links\" | \"PUT /internal/apm/settings/custom_links/{id}\" | \"DELETE /internal/apm/settings/custom_links/{id}\" | \"GET /api/apm/sourcemaps\" | \"POST /api/apm/sourcemaps\" | \"DELETE /api/apm/sourcemaps/{id}\" | \"POST /internal/apm/sourcemaps/migrate_fleet_artifacts\" | \"GET /internal/apm/fleet/has_apm_policies\" | \"GET /internal/apm/fleet/agents\" | \"POST /api/apm/fleet/apm_server_schema\" | \"GET /internal/apm/fleet/apm_server_schema/unsupported\" | \"GET /internal/apm/fleet/migration_check\" | \"POST /internal/apm/fleet/cloud_apm_package_policy\" | \"GET /internal/apm/fleet/java_agent_versions\" | \"GET /internal/apm/dependencies/top_dependencies\" | \"GET /internal/apm/dependencies/upstream_services\" | \"GET /internal/apm/dependencies/metadata\" | \"GET /internal/apm/dependencies/charts/latency\" | \"GET /internal/apm/dependencies/charts/throughput\" | \"GET /internal/apm/dependencies/charts/error_rate\" | \"GET /internal/apm/dependencies/operations\" | \"GET /internal/apm/dependencies/charts/distribution\" | \"GET /internal/apm/dependencies/operations/spans\" | \"GET /internal/apm/correlations/field_candidates/transactions\" | \"GET /internal/apm/correlations/field_value_stats/transactions\" | \"POST /internal/apm/correlations/field_value_pairs/transactions\" | \"POST /internal/apm/correlations/significant_correlations/transactions\" | \"POST /internal/apm/correlations/p_values/transactions\" | \"GET /internal/apm/fallback_to_transactions\" | \"GET /internal/apm/has_data\" | \"GET /internal/apm/event_metadata/{processorEvent}/{id}\" | \"GET /internal/apm/agent_keys\" | \"GET /internal/apm/agent_keys/privileges\" | \"POST /internal/apm/api_key/invalidate\" | \"POST /api/apm/agent_keys\" | \"GET /internal/apm/storage_explorer\" | \"GET /internal/apm/services/{serviceName}/storage_details\" | \"GET /internal/apm/storage_chart\" | \"GET /internal/apm/storage_explorer/privileges\" | \"GET /internal/apm/storage_explorer_summary_stats\" | \"GET /internal/apm/storage_explorer/is_cross_cluster_search\" | \"GET /internal/apm/storage_explorer/get_services\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/parents\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/children\" | \"GET /internal/apm/services/{serviceName}/infrastructure_attributes\" | \"GET /internal/apm/debug-telemetry\" | \"GET /internal/apm/time_range_metadata\" | \"GET /internal/apm/settings/labs\" | \"GET /internal/apm/get_agents_per_service\" | \"GET /internal/apm/services/{serviceName}/agent_instances\" | \"GET /internal/apm/services/{serviceName}/mobile/filters\" | \"GET /internal/apm/mobile-services/{serviceName}/transactions/charts/sessions\" | \"GET /internal/apm/mobile-services/{serviceName}/transactions/charts/http_requests\" | \"GET /internal/apm/mobile-services/{serviceName}/stats\" | \"GET /internal/apm/mobile-services/{serviceName}/location/stats\" | \"GET /internal/apm/mobile-services/{serviceName}/terms\"" + "\"POST /internal/apm/data_view/static\" | \"GET /internal/apm/data_view/title\" | \"GET /internal/apm/environments\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics_by_transaction_name\" | \"POST /internal/apm/services/{serviceName}/errors/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/samples\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/error/{errorId}\" | \"GET /internal/apm/services/{serviceName}/errors/distribution\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/top_erroneous_transactions\" | \"POST /internal/apm/latency/overall_distribution/transactions\" | \"GET /internal/apm/services/{serviceName}/metrics/charts\" | \"GET /internal/apm/services/{serviceName}/metrics/nodes\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/charts\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/summary\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/functions_overview\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/active_instances\" | \"GET /internal/apm/observability_overview\" | \"GET /internal/apm/observability_overview/has_data\" | \"GET /internal/apm/service-map\" | \"GET /internal/apm/service-map/service/{serviceName}\" | \"GET /internal/apm/service-map/dependency\" | \"GET /internal/apm/services\" | \"POST /internal/apm/services/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/metadata/details\" | \"GET /internal/apm/services/{serviceName}/metadata/icons\" | \"GET /internal/apm/services/{serviceName}/agent\" | \"GET /internal/apm/services/{serviceName}/transaction_types\" | \"GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata\" | \"GET /api/apm/services/{serviceName}/annotation/search\" | \"POST /api/apm/services/{serviceName}/annotation\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\" | \"GET /internal/apm/services/{serviceName}/throughput\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/dependencies\" | \"GET /internal/apm/services/{serviceName}/dependencies/breakdown\" | \"GET /internal/apm/services/{serviceName}/anomaly_charts\" | \"GET /internal/apm/services/{serviceName}/alerts_count\" | \"GET /internal/apm/service-groups\" | \"GET /internal/apm/service-group\" | \"POST /internal/apm/service-group\" | \"DELETE /internal/apm/service-group\" | \"GET /internal/apm/service-group/services\" | \"GET /internal/apm/service-group/counts\" | \"GET /internal/apm/suggestions\" | \"GET /internal/apm/traces/{traceId}\" | \"GET /internal/apm/traces\" | \"GET /internal/apm/traces/{traceId}/root_transaction\" | \"GET /internal/apm/transactions/{transactionId}\" | \"GET /internal/apm/traces/find\" | \"POST /internal/apm/traces/aggregated_critical_path\" | \"GET /internal/apm/traces/{traceId}/transactions/{transactionId}\" | \"GET /internal/apm/traces/{traceId}/spans/{spanId}\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/latency\" | \"GET /internal/apm/services/{serviceName}/transactions/traces/samples\" | \"GET /internal/apm/services/{serviceName}/transaction/charts/breakdown\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/error_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate_by_transaction_name\" | \"GET /internal/apm/rule_types/transaction_error_rate/chart_preview\" | \"GET /internal/apm/rule_types/transaction_duration/chart_preview\" | \"GET /internal/apm/rule_types/error_count/chart_preview\" | \"GET /api/apm/settings/agent-configuration\" | \"GET /api/apm/settings/agent-configuration/view\" | \"DELETE /api/apm/settings/agent-configuration\" | \"PUT /api/apm/settings/agent-configuration\" | \"POST /api/apm/settings/agent-configuration/search\" | \"GET /api/apm/settings/agent-configuration/environments\" | \"GET /api/apm/settings/agent-configuration/agent_name\" | \"GET /internal/apm/settings/anomaly-detection/jobs\" | \"POST /internal/apm/settings/anomaly-detection/jobs\" | \"GET /internal/apm/settings/anomaly-detection/environments\" | \"POST /internal/apm/settings/anomaly-detection/update_to_v3\" | \"GET /internal/apm/settings/apm-index-settings\" | \"GET /internal/apm/settings/apm-indices\" | \"POST /internal/apm/settings/apm-indices/save\" | \"GET /internal/apm/settings/custom_links/transaction\" | \"GET /internal/apm/settings/custom_links\" | \"POST /internal/apm/settings/custom_links\" | \"PUT /internal/apm/settings/custom_links/{id}\" | \"DELETE /internal/apm/settings/custom_links/{id}\" | \"GET /api/apm/sourcemaps\" | \"POST /api/apm/sourcemaps\" | \"DELETE /api/apm/sourcemaps/{id}\" | \"POST /internal/apm/sourcemaps/migrate_fleet_artifacts\" | \"GET /internal/apm/fleet/has_apm_policies\" | \"GET /internal/apm/fleet/agents\" | \"POST /api/apm/fleet/apm_server_schema\" | \"GET /internal/apm/fleet/apm_server_schema/unsupported\" | \"GET /internal/apm/fleet/migration_check\" | \"POST /internal/apm/fleet/cloud_apm_package_policy\" | \"GET /internal/apm/fleet/java_agent_versions\" | \"GET /internal/apm/dependencies/top_dependencies\" | \"GET /internal/apm/dependencies/upstream_services\" | \"GET /internal/apm/dependencies/metadata\" | \"GET /internal/apm/dependencies/charts/latency\" | \"GET /internal/apm/dependencies/charts/throughput\" | \"GET /internal/apm/dependencies/charts/error_rate\" | \"GET /internal/apm/dependencies/operations\" | \"GET /internal/apm/dependencies/charts/distribution\" | \"GET /internal/apm/dependencies/operations/spans\" | \"GET /internal/apm/correlations/field_candidates/transactions\" | \"GET /internal/apm/correlations/field_value_stats/transactions\" | \"POST /internal/apm/correlations/field_value_pairs/transactions\" | \"POST /internal/apm/correlations/significant_correlations/transactions\" | \"POST /internal/apm/correlations/p_values/transactions\" | \"GET /internal/apm/fallback_to_transactions\" | \"GET /internal/apm/has_data\" | \"GET /internal/apm/event_metadata/{processorEvent}/{id}\" | \"GET /internal/apm/agent_keys\" | \"GET /internal/apm/agent_keys/privileges\" | \"POST /internal/apm/api_key/invalidate\" | \"POST /api/apm/agent_keys\" | \"GET /internal/apm/storage_explorer\" | \"GET /internal/apm/services/{serviceName}/storage_details\" | \"GET /internal/apm/storage_chart\" | \"GET /internal/apm/storage_explorer/privileges\" | \"GET /internal/apm/storage_explorer_summary_stats\" | \"GET /internal/apm/storage_explorer/is_cross_cluster_search\" | \"GET /internal/apm/storage_explorer/get_services\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/parents\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/children\" | \"GET /internal/apm/services/{serviceName}/infrastructure_attributes\" | \"GET /internal/apm/debug-telemetry\" | \"GET /internal/apm/time_range_metadata\" | \"GET /internal/apm/settings/labs\" | \"GET /internal/apm/get_agents_per_service\" | \"GET /internal/apm/get_latest_agent_versions\" | \"GET /internal/apm/services/{serviceName}/agent_instances\" | \"GET /internal/apm/services/{serviceName}/mobile/filters\" | \"GET /internal/apm/mobile-services/{serviceName}/transactions/charts/sessions\" | \"GET /internal/apm/mobile-services/{serviceName}/transactions/charts/http_requests\" | \"GET /internal/apm/mobile-services/{serviceName}/stats\" | \"GET /internal/apm/mobile-services/{serviceName}/location/stats\" | \"GET /internal/apm/mobile-services/{serviceName}/terms\"" ], "path": "x-pack/plugins/apm/server/routes/apm_routes/get_global_apm_server_route_repository.ts", "deprecated": false, @@ -842,7 +853,7 @@ "signature": [ "{ readonly indices: Readonly<{} & { error: string; metric: string; span: string; transaction: string; onboarding: string; }>; readonly autoCreateApmDataView: boolean; readonly serviceMapEnabled: boolean; readonly serviceMapFingerprintBucketSize: number; readonly serviceMapFingerprintGlobalBucketSize: number; readonly serviceMapTraceIdBucketSize: number; readonly serviceMapTraceIdGlobalBucketSize: number; readonly serviceMapMaxTracesPerRequest: number; readonly ui: Readonly<{} & { enabled: boolean; maxTraceItems: number; }>; readonly searchAggregatedTransactions: ", "SearchAggregatedTransactionSetting", - "; readonly telemetryCollectionEnabled: boolean; readonly metricsInterval: number; readonly agent: Readonly<{} & { migrations: Readonly<{} & { enabled: boolean; }>; }>; readonly forceSyntheticSource: boolean; }" + "; readonly telemetryCollectionEnabled: boolean; readonly metricsInterval: number; readonly agent: Readonly<{} & { migrations: Readonly<{} & { enabled: boolean; }>; }>; readonly forceSyntheticSource: boolean; readonly latestAgentVersionsUrl: string; }" ], "path": "x-pack/plugins/apm/server/index.ts", "deprecated": false, @@ -1328,6 +1339,26 @@ "AgentExplorerAgentInstancesResponse", "; }, ", "APMRouteCreateOptions", + ">; \"GET /internal/apm/get_latest_agent_versions\": ", + { + "pluginId": "@kbn/server-route-repository", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"GET /internal/apm/get_latest_agent_versions\", undefined, ", + { + "pluginId": "apm", + "scope": "server", + "docId": "kibApmPluginApi", + "section": "def-server.APMRouteHandlerResources", + "text": "APMRouteHandlerResources" + }, + ", ", + "AgentLatestVersionsResponse", + ", ", + "APMRouteCreateOptions", ">; \"GET /internal/apm/get_agents_per_service\": ", { "pluginId": "@kbn/server-route-repository", @@ -7895,7 +7926,7 @@ "Observable", "<Readonly<{} & { indices: Readonly<{} & { error: string; metric: string; span: string; transaction: string; onboarding: string; }>; autoCreateApmDataView: boolean; serviceMapEnabled: boolean; serviceMapFingerprintBucketSize: number; serviceMapFingerprintGlobalBucketSize: number; serviceMapTraceIdBucketSize: number; serviceMapTraceIdGlobalBucketSize: number; serviceMapMaxTracesPerRequest: number; ui: Readonly<{} & { enabled: boolean; maxTraceItems: number; }>; searchAggregatedTransactions: ", "SearchAggregatedTransactionSetting", - "; telemetryCollectionEnabled: boolean; metricsInterval: number; agent: Readonly<{} & { migrations: Readonly<{} & { enabled: boolean; }>; }>; forceSyntheticSource: boolean; }>>" + "; telemetryCollectionEnabled: boolean; metricsInterval: number; agent: Readonly<{} & { migrations: Readonly<{} & { enabled: boolean; }>; }>; forceSyntheticSource: boolean; latestAgentVersionsUrl: string; }>>" ], "path": "x-pack/plugins/apm/server/types.ts", "deprecated": false, diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index 671e083218d2c..f10b4d9e334ba 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/apm-ui](https://github.com/orgs/elastic/teams/apm-ui) for ques | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 42 | 0 | 42 | 108 | +| 43 | 0 | 43 | 109 | ## Client diff --git a/api_docs/asset_manager.mdx b/api_docs/asset_manager.mdx index 0c297f05ea63f..a21b20cdd09d4 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'assetManager'] --- import assetManagerObj from './asset_manager.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index 1c01a8b448f76..a6199c06521f3 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: 2023-04-11 +date: 2023-04-12 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 1113903cdff36..e399e7d6d9c26 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: 2023-04-11 +date: 2023-04-12 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 52434e5db2cd3..d88205796ae34 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: 2023-04-11 +date: 2023-04-12 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 a4e4eb54b9eb2..004bf1b69f7d7 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: 2023-04-11 +date: 2023-04-12 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 ce7792ef809cf..81c703ea6c06d 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: 2023-04-11 +date: 2023-04-12 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 64927b1d3b8b2..73fe3790799a0 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_chat.mdx b/api_docs/cloud_chat.mdx index a273bc5fd15b6..1012b7a71be51 100644 --- a/api_docs/cloud_chat.mdx +++ b/api_docs/cloud_chat.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudChat title: "cloudChat" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudChat plugin -date: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudChat'] --- import cloudChatObj from './cloud_chat.devdocs.json'; diff --git a/api_docs/cloud_data_migration.mdx b/api_docs/cloud_data_migration.mdx index ab916f26452f6..9073d96065ec0 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: 2023-04-11 +date: 2023-04-12 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 465a9806a02b3..6bc1bdb30df38 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: 2023-04-11 +date: 2023-04-12 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 2afa4ec8b27c2..1b6f7ffc8e4ef 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: 2023-04-11 +date: 2023-04-12 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 0ecff99147aa9..b633e7690dcf5 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: 2023-04-11 +date: 2023-04-12 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 561cc7ec249f4..05749998de72d 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: 2023-04-11 +date: 2023-04-12 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 0b3f7f2878a80..b12c874d5dc5d 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: 2023-04-11 +date: 2023-04-12 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 8d8e9bc3833d7..6a2402701049a 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: 2023-04-11 +date: 2023-04-12 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 90ab6fc4947a8..c2f38b4e284c7 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: 2023-04-11 +date: 2023-04-12 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 cee79df7367d6..af7615b43e632 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: 2023-04-11 +date: 2023-04-12 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 c7f27d35856ed..dcd69fdf25ede 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.devdocs.json b/api_docs/data.devdocs.json index 43b72b05c743f..a5fc6da9e9a3d 100644 --- a/api_docs/data.devdocs.json +++ b/api_docs/data.devdocs.json @@ -10841,22 +10841,6 @@ "plugin": "osquery", "path": "x-pack/plugins/osquery/public/assets/use_assets_status.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx" - }, { "plugin": "synthetics", "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/monitor_detail_flyout.tsx" @@ -28674,22 +28658,6 @@ "plugin": "osquery", "path": "x-pack/plugins/osquery/public/assets/use_assets_status.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx" - }, { "plugin": "synthetics", "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/monitor_detail_flyout.tsx" diff --git a/api_docs/data.mdx b/api_docs/data.mdx index c6dfda2725f4e..d21da2dbf0cce 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index e1574029d92c4..32b7235a1c195 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: 2023-04-11 +date: 2023-04-12 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 9918e5fd40c66..372b8358fac44 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: 2023-04-11 +date: 2023-04-12 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 f9c80bea8d515..ac6aa616b9869 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: 2023-04-11 +date: 2023-04-12 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 55e12130750db..57ef446d0e764 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: 2023-04-11 +date: 2023-04-12 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 c46a9ac00e9ff..5ea0b9d1bab84 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.devdocs.json b/api_docs/data_views.devdocs.json index bfd5dafc1484a..2007675704479 100644 --- a/api_docs/data_views.devdocs.json +++ b/api_docs/data_views.devdocs.json @@ -26209,22 +26209,6 @@ "plugin": "osquery", "path": "x-pack/plugins/osquery/public/assets/use_assets_status.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx" - }, { "plugin": "synthetics", "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/monitor_detail_flyout.tsx" diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index 0f298cfae4619..7568ff0227276 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: 2023-04-11 +date: 2023-04-12 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 2645c7a559578..685099805b596 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index 86f322477079d..a4a8758df91dc 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -23,10 +23,10 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | <DocLink id="kibKibanaReactPluginApi" section="def-public.RedirectAppLinks" text="RedirectAppLinks"/> | home, data, esUiShared, spaces, savedObjectsManagement, observability, exploratoryView, fleet, ml, apm, enterpriseSearch, indexLifecycleManagement, synthetics, upgradeAssistant, ux, kibanaOverview | - | | <DocLink id="kibSecurityPluginApi" section="def-server.SecurityPluginSetup.authc" text="authc"/> | encryptedSavedObjects, actions, data, ml, logstash, securitySolution, cloudChat | - | | <DocLink id="kibSecurityPluginApi" section="def-server.SecurityPluginSetup.authz" text="authz"/> | actions, ml, savedObjectsTagging, enterpriseSearch | - | -| <DocLink id="kibKbnCoreLifecycleBrowserPluginApi" section="def-common.CoreStart.savedObjects" text="savedObjects"/> | @kbn/core-plugins-browser-internal, @kbn/core-root-browser-internal, dataViews, home, data, savedObjects, unifiedSearch, presentationUtil, visualizations, dashboard, lens, discover, fileUpload, maps, ml, infra, fleet, canvas, dashboardEnhanced, graph, monitoring, synthetics, transform, watcher, dataVisualizer, cloudSecurityPosture, securitySolution | - | -| <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract" text="SavedObjectsClientContract"/> | @kbn/core-saved-objects-browser, @kbn/core-saved-objects-browser-internal, @kbn/core, dataViews, home, savedObjects, savedSearch, visualizations, dashboard, lens, ml, canvas, graph, securitySolution, synthetics, watcher, visTypeTimeseries, @kbn/core-saved-objects-browser-mocks | - | +| <DocLink id="kibKbnCoreLifecycleBrowserPluginApi" section="def-common.CoreStart.savedObjects" text="savedObjects"/> | @kbn/core-plugins-browser-internal, @kbn/core-root-browser-internal, dataViews, home, data, savedObjects, unifiedSearch, presentationUtil, visualizations, dashboard, lens, discover, fileUpload, maps, ml, infra, fleet, canvas, dashboardEnhanced, graph, monitoring, synthetics, transform, dataVisualizer, cloudSecurityPosture, securitySolution | - | +| <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract" text="SavedObjectsClientContract"/> | @kbn/core-saved-objects-browser, @kbn/core-saved-objects-browser-internal, @kbn/core, dataViews, home, savedObjects, savedSearch, visualizations, dashboard, lens, ml, canvas, graph, visTypeTimeseries, @kbn/core-saved-objects-browser-mocks | - | | <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract.find" text="find"/> | @kbn/core-saved-objects-browser-mocks, dataViews, savedObjects, presentationUtil, savedSearch, visualizations, dashboard, lens, maps, ml, infra, cloudSecurityPosture, dashboardEnhanced, graph, securitySolution, synthetics, @kbn/core-saved-objects-browser-internal | - | -| <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract.get" text="get"/> | @kbn/core-saved-objects-browser-mocks, dataViews, savedObjects, visualizations, dashboard, ml, infra, cloudSecurityPosture, dashboardEnhanced, monitoring, synthetics, @kbn/core-saved-objects-browser-internal | - | +| <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract.get" text="get"/> | @kbn/core-saved-objects-browser-mocks, dataViews, savedObjects, visualizations, dashboard, ml, infra, cloudSecurityPosture, dashboardEnhanced, monitoring, @kbn/core-saved-objects-browser-internal | - | | <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SimpleSavedObject" text="SimpleSavedObject"/> | @kbn/core-saved-objects-browser-internal, @kbn/core, dataViews, savedObjects, embeddable, presentationUtil, visualizations, dashboard, lens, aiops, ml, maps, dataVisualizer, infra, fleet, cloudSecurityPosture, dashboardEnhanced, graph, synthetics, securitySolution, @kbn/core-saved-objects-browser-mocks | - | | <DocLink id="kibKbnCoreSavedObjectsBrowserMocksPluginApi" section="def-common.savedObjectsServiceMock" text="savedObjectsServiceMock"/> | @kbn/core-lifecycle-browser-mocks, @kbn/core, ml, dashboard, dataViews, savedSearch, @kbn/core-plugins-browser-internal | - | | <DocLink id="kibKbnCoreSavedObjectsCommonPluginApi" section="def-common.SavedObjectAttributes" text="SavedObjectAttributes"/> | @kbn/core, savedObjects, embeddable, visualizations, dashboard, fleet, infra, canvas, graph, ml, @kbn/core-saved-objects-common, @kbn/core-saved-objects-server, actions, alerting, savedSearch, enterpriseSearch, securitySolution, taskManager, @kbn/core-saved-objects-server-internal, @kbn/core-saved-objects-api-server | - | @@ -41,8 +41,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | <DocLink id="kibDataPluginApi" section="def-common.EsQuerySearchAfter" text="EsQuerySearchAfter"/> | discover | - | | <DocLink id="kibUiActionsPluginApi" section="def-public.UiActionsService.executeTriggerActions" text="executeTriggerActions"/> | data, discover, imageEmbeddable, embeddable | - | | <DocLink id="kibKbnCoreUiSettingsCommonPluginApi" section="def-common.UiSettingsParams.metric" text="metric"/> | advancedSettings, discover | - | -| <DocLink id="kibDataPluginApi" section="def-public.SavedObject" text="SavedObject"/> | @kbn/core-saved-objects-common, @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-api-server, @kbn/core, home, dataViews, savedObjectsTagging, fleet, canvas, osquery, securitySolution, synthetics, savedObjects, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-import-export-server-internal, savedObjectsTaggingOss, cases, lists, upgradeAssistant, savedObjectsManagement, @kbn/core-ui-settings-server-internal, dashboard | - | -| <DocLink id="kibDataPluginApi" section="def-common.SavedObject" text="SavedObject"/> | @kbn/core-saved-objects-common, @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-api-server, @kbn/core, home, dataViews, savedObjectsTagging, fleet, canvas, osquery, securitySolution, synthetics, savedObjects, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-import-export-server-internal, savedObjectsTaggingOss, cases, lists, upgradeAssistant, savedObjectsManagement, @kbn/core-ui-settings-server-internal, data | - | +| <DocLink id="kibDataPluginApi" section="def-public.SavedObject" text="SavedObject"/> | @kbn/core-saved-objects-common, @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-api-server, @kbn/core, home, dataViews, savedObjectsTagging, fleet, canvas, osquery, synthetics, savedObjects, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-import-export-server-internal, savedObjectsTaggingOss, cases, lists, securitySolution, upgradeAssistant, savedObjectsManagement, @kbn/core-ui-settings-server-internal, dashboard | - | +| <DocLink id="kibDataPluginApi" section="def-common.SavedObject" text="SavedObject"/> | @kbn/core-saved-objects-common, @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-api-server, @kbn/core, home, dataViews, savedObjectsTagging, fleet, canvas, osquery, synthetics, savedObjects, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-import-export-server-internal, savedObjectsTaggingOss, cases, lists, securitySolution, upgradeAssistant, savedObjectsManagement, @kbn/core-ui-settings-server-internal, data | - | | <DocLink id="kibDataPluginApi" section="def-common.EqlSearchStrategyRequest.options" text="options"/> | securitySolution | - | | <DocLink id="kibKbnCoreSavedObjectsApiServerPluginApi" section="def-common.SavedObject.migrationVersion" text="migrationVersion"/> | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, home, fleet, graph, lists, securitySolution | - | | <DocLink id="kibKbnSecuritysolutionListConstantsPluginApi" section="def-common.ENDPOINT_TRUSTED_APPS_LIST_ID" text="ENDPOINT_TRUSTED_APPS_LIST_ID"/> | lists, securitySolution, @kbn/securitysolution-io-ts-list-types | - | @@ -59,7 +59,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | <DocLink id="kibKbnSecuritysolutionListConstantsPluginApi" section="def-common.ENDPOINT_BLOCKLISTS_LIST_DESCRIPTION" text="ENDPOINT_BLOCKLISTS_LIST_DESCRIPTION"/> | securitySolution | - | | <DocLink id="kibDataPluginApi" section="def-public.syncQueryStateWithUrl" text="syncQueryStateWithUrl"/> | monitoring | - | | <DocLink id="kibKbnCoreSavedObjectsCommonPluginApi" section="def-common.SavedObjectReference" text="SavedObjectReference"/> | @kbn/core-saved-objects-api-browser, @kbn/core, savedObjects, savedObjectsManagement, visualizations, savedObjectsTagging, lens, fleet, graph, dashboard, savedObjectsTaggingOss, kibanaUtils, expressions, dataViews, data, embeddable, controls, uiActionsEnhanced, cases, maps, canvas, dashboardEnhanced, globalSearchProviders, infra | - | -| <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract.create" text="create"/> | @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, dataViews, savedObjects, savedSearch, visualizations, dashboard, lens, maps, infra, graph, synthetics | - | +| <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract.create" text="create"/> | @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, dataViews, savedObjects, savedSearch, visualizations, dashboard, lens, maps, infra, graph | - | | <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract.bulkCreate" text="bulkCreate"/> | @kbn/core-saved-objects-browser-mocks, home, @kbn/core-saved-objects-browser-internal | - | | <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract.delete" text="delete"/> | @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, dataViews, savedObjects, visualizations, dashboard, maps, infra, graph | - | | <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract.bulkDelete" text="bulkDelete"/> | @kbn/core-saved-objects-browser-mocks, synthetics, @kbn/core-saved-objects-browser-internal | - | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 730f0dcb1db18..f5fceb84f772d 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -1132,9 +1132,9 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | ---------------|-----------|-----------| | <DocLink id="kibDataPluginApi" section="def-public.SearchSource.create" text="create"/> | [wrap_search_source_client.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.ts#:~:text=create) | - | | <DocLink id="kibDataPluginApi" section="def-public.SearchSource.fetch" text="fetch"/> | [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch) | - | -| <DocLink id="kibDataPluginApi" section="def-public.SavedObject" text="SavedObject"/> | [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts#:~:text=SavedObject), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts#:~:text=SavedObject), [use_security_dashboards_table.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx#:~:text=SavedObject), [use_security_dashboards_table.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx#:~:text=SavedObject), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject), [user_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/user_risk_score_dashboards.ts#:~:text=SavedObject), [user_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/user_risk_score_dashboards.ts#:~:text=SavedObject) | - | +| <DocLink id="kibDataPluginApi" section="def-public.SavedObject" text="SavedObject"/> | [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject), [user_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/user_risk_score_dashboards.ts#:~:text=SavedObject), [user_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/user_risk_score_dashboards.ts#:~:text=SavedObject) | - | | <DocLink id="kibDataPluginApi" section="def-public.DataPublicPluginStart.indexPatterns" text="indexPatterns"/> | [dependencies_start_mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/mock/endpoint/dependencies_start_mock.ts#:~:text=indexPatterns) | - | -| <DocLink id="kibDataPluginApi" section="def-common.SavedObject" text="SavedObject"/> | [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts#:~:text=SavedObject), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts#:~:text=SavedObject), [use_security_dashboards_table.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx#:~:text=SavedObject), [use_security_dashboards_table.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx#:~:text=SavedObject), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject), [user_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/user_risk_score_dashboards.ts#:~:text=SavedObject), [user_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/user_risk_score_dashboards.ts#:~:text=SavedObject), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts#:~:text=SavedObject), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts#:~:text=SavedObject)+ 14 more | - | +| <DocLink id="kibDataPluginApi" section="def-common.SavedObject" text="SavedObject"/> | [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject), [user_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/user_risk_score_dashboards.ts#:~:text=SavedObject), [user_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/user_risk_score_dashboards.ts#:~:text=SavedObject), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject), [user_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/user_risk_score_dashboards.ts#:~:text=SavedObject), [user_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/user_risk_score_dashboards.ts#:~:text=SavedObject), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject)+ 2 more | - | | <DocLink id="kibDataPluginApi" section="def-common.DataView.title" text="title"/> | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=title), [use_rule_from_timeline.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.tsx#:~:text=title), [get_es_query_filter.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts#:~:text=title), [alerts_grouping.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.tsx#:~:text=title), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts#:~:text=title), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=title), [get_query_filter.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/get_query_filter.ts#:~:text=title), [index_pattern.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/mock/index_pattern.ts#:~:text=title), [utils.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/alerts_actions/utils.test.ts#:~:text=title)+ 20 more | - | | <DocLink id="kibDataPluginApi" section="def-common.SearchSource.create" text="create"/> | [wrap_search_source_client.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.ts#:~:text=create) | - | | <DocLink id="kibDataPluginApi" section="def-common.SearchSource.fetch" text="fetch"/> | [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch) | - | @@ -1145,9 +1145,8 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | <DocLink id="kibLicensingPluginApi" section="def-server.PublicLicense.mode" text="mode"/> | [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode)+ 7 more | 8.8.0 | | <DocLink id="kibLicensingPluginApi" section="def-server.LicensingPluginSetup.license$" text="license$"/> | [query.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts#:~:text=license%24) | 8.8.0 | | <DocLink id="kibSecurityPluginApi" section="def-server.SecurityPluginSetup.authc" text="authc"/> | [request_context_factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/request_context_factory.ts#:~:text=authc), [route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts#:~:text=authc), [create_signals_migration_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts#:~:text=authc), [delete_signals_migration_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts#:~:text=authc), [finalize_signals_migration_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts#:~:text=authc), [open_close_signals_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts#:~:text=authc), [common.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts#:~:text=authc) | - | -| <DocLink id="kibKbnCoreLifecycleBrowserPluginApi" section="def-common.CoreStart.savedObjects" text="savedObjects"/> | [use_dashboard_button_href.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/use_dashboard_button_href.ts#:~:text=savedObjects), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/index.tsx#:~:text=savedObjects), [use_security_dashboards_table.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx#:~:text=savedObjects), [use_create_security_dashboard_link.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/use_create_security_dashboard_link.ts#:~:text=savedObjects) | - | -| <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract" text="SavedObjectsClientContract"/> | [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts#:~:text=SavedObjectsClientContract), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts#:~:text=SavedObjectsClientContract), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts#:~:text=SavedObjectsClientContract), [utils.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/utils.test.ts#:~:text=SavedObjectsClientContract), [utils.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/utils.test.ts#:~:text=SavedObjectsClientContract) | - | -| <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract.find" text="find"/> | [use_dashboard_button_href.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/use_dashboard_button_href.ts#:~:text=find), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/index.tsx#:~:text=find), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/index.tsx#:~:text=find), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts#:~:text=find), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts#:~:text=find) | - | +| <DocLink id="kibKbnCoreLifecycleBrowserPluginApi" section="def-common.CoreStart.savedObjects" text="savedObjects"/> | [use_dashboard_button_href.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/use_dashboard_button_href.ts#:~:text=savedObjects), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/index.tsx#:~:text=savedObjects) | - | +| <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract.find" text="find"/> | [use_dashboard_button_href.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/use_dashboard_button_href.ts#:~:text=find), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/index.tsx#:~:text=find), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/index.tsx#:~:text=find) | - | | <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SimpleSavedObject" text="SimpleSavedObject"/> | [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/types.ts#:~:text=SimpleSavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/types.ts#:~:text=SimpleSavedObject) | - | | <DocLink id="kibKbnCoreSavedObjectsApiServerPluginApi" section="def-common.SavedObject.migrationVersion" text="migrationVersion"/> | [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion)+ 44 more | - | | <DocLink id="kibKbnCoreSavedObjectsApiServerPluginApi" section="def-common.SavedObjectAttributes" text="SavedObjectAttributes"/> | [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes), [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes) | - | @@ -1211,15 +1210,12 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | <DocLink id="kibDataPluginApi" section="def-common.DataView.title" text="title"/> | [filter_group.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/filter_group/filter_group.tsx#:~:text=title), [filters_expression_select.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/alerts/monitor_expressions/filters_expression_select.tsx#:~:text=title), [filter_group.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/filter_group/filter_group.tsx#:~:text=title), [filters_expression_select.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/alerts/monitor_expressions/filters_expression_select.tsx#:~:text=title) | - | | <DocLink id="kibDataPluginApi" section="def-server.DataView.title" text="title"/> | [filter_group.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/filter_group/filter_group.tsx#:~:text=title), [filters_expression_select.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/alerts/monitor_expressions/filters_expression_select.tsx#:~:text=title), [filter_group.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/filter_group/filter_group.tsx#:~:text=title), [filters_expression_select.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/alerts/monitor_expressions/filters_expression_select.tsx#:~:text=title) | - | | <DocLink id="kibDataViewsPluginApi" section="def-public.DataView.title" text="title"/> | [filter_group.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/filter_group/filter_group.tsx#:~:text=title), [filters_expression_select.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/alerts/monitor_expressions/filters_expression_select.tsx#:~:text=title) | - | -| <DocLink id="kibDiscoverPluginApi" section="def-common.DiscoverAppLocatorParams.indexPatternId" text="indexPatternId"/> | [stderr_logs.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/synthetics/check_steps/stderr_logs.tsx#:~:text=indexPatternId), [stderr_logs.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/stderr_logs.tsx#:~:text=indexPatternId) | - | +| <DocLink id="kibDiscoverPluginApi" section="def-common.DiscoverAppLocatorParams.indexPatternId" text="indexPatternId"/> | [stderr_logs.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/stderr_logs.tsx#:~:text=indexPatternId) | - | | <DocLink id="kibKibanaReactPluginApi" section="def-public.RedirectAppLinks" text="RedirectAppLinks"/> | [alert_messages.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/lib/alert_types/alert_messages.tsx#:~:text=RedirectAppLinks), [alert_messages.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/lib/alert_types/alert_messages.tsx#:~:text=RedirectAppLinks), [alert_messages.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/lib/alert_types/alert_messages.tsx#:~:text=RedirectAppLinks), [uptime_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/app/uptime_app.tsx#:~:text=RedirectAppLinks), [uptime_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/app/uptime_app.tsx#:~:text=RedirectAppLinks), [uptime_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/app/uptime_app.tsx#:~:text=RedirectAppLinks), [synthetics_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/synthetics_app.tsx#:~:text=RedirectAppLinks), [synthetics_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/synthetics_app.tsx#:~:text=RedirectAppLinks), [synthetics_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/synthetics_app.tsx#:~:text=RedirectAppLinks) | - | -| <DocLink id="kibKbnCoreLifecycleBrowserPluginApi" section="def-common.CoreStart.savedObjects" text="savedObjects"/> | [use_filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/monitor_filters/use_filters.ts#:~:text=savedObjects), [use_monitor_name.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/monitor_config/use_monitor_name.ts#:~:text=savedObjects), [use_location_monitors.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/manage_locations/hooks/use_location_monitors.ts#:~:text=savedObjects), [use_locations_api.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/manage_locations/hooks/use_locations_api.ts#:~:text=savedObjects), [use_invalid_monitors.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/hooks/use_invalid_monitors.tsx#:~:text=savedObjects), [use_recently_viewed_monitors.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_selector/use_recently_viewed_monitors.ts#:~:text=savedObjects), [delete_param.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx#:~:text=savedObjects), [use_location_monitors.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/private_locations/hooks/use_location_monitors.ts#:~:text=savedObjects), [use_monitor_name.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/hooks/use_monitor_name.ts#:~:text=savedObjects), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/plugin.ts#:~:text=savedObjects) | - | -| <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract" text="SavedObjectsClientContract"/> | [api.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/state/private_locations/api.ts#:~:text=SavedObjectsClientContract), [api.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/state/private_locations/api.ts#:~:text=SavedObjectsClientContract), [api.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/state/private_locations/api.ts#:~:text=SavedObjectsClientContract) | - | -| <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract.create" text="create"/> | [api.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/state/private_locations/api.ts#:~:text=create) | - | +| <DocLink id="kibKbnCoreLifecycleBrowserPluginApi" section="def-common.CoreStart.savedObjects" text="savedObjects"/> | [use_filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/monitor_filters/use_filters.ts#:~:text=savedObjects), [use_recently_viewed_monitors.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_selector/use_recently_viewed_monitors.ts#:~:text=savedObjects), [delete_param.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx#:~:text=savedObjects), [use_location_monitors.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/private_locations/hooks/use_location_monitors.ts#:~:text=savedObjects), [use_monitor_name.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/hooks/use_monitor_name.ts#:~:text=savedObjects), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/plugin.ts#:~:text=savedObjects) | - | | <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract.bulkDelete" text="bulkDelete"/> | [delete_param.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx#:~:text=bulkDelete) | - | -| <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract.find" text="find"/> | [use_filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/monitor_filters/use_filters.ts#:~:text=find), [use_monitor_name.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/monitor_config/use_monitor_name.ts#:~:text=find), [use_location_monitors.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/manage_locations/hooks/use_location_monitors.ts#:~:text=find), [use_location_monitors.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/private_locations/hooks/use_location_monitors.ts#:~:text=find), [use_monitor_name.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/hooks/use_monitor_name.ts#:~:text=find), [use_filters.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/monitor_filters/use_filters.test.ts#:~:text=find), [use_filters.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/monitor_filters/use_filters.test.ts#:~:text=find) | - | -| <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract.get" text="get"/> | [api.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/state/private_locations/api.ts#:~:text=get) | - | -| <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract.bulkResolve" text="bulkResolve"/> | [use_invalid_monitors.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/hooks/use_invalid_monitors.tsx#:~:text=bulkResolve), [use_recently_viewed_monitors.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_selector/use_recently_viewed_monitors.ts#:~:text=bulkResolve) | - | +| <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract.find" text="find"/> | [use_filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/monitor_filters/use_filters.ts#:~:text=find), [use_location_monitors.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/private_locations/hooks/use_location_monitors.ts#:~:text=find), [use_monitor_name.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/hooks/use_monitor_name.ts#:~:text=find), [use_filters.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/monitor_filters/use_filters.test.ts#:~:text=find), [use_filters.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/monitor_filters/use_filters.test.ts#:~:text=find) | - | +| <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract.bulkResolve" text="bulkResolve"/> | [use_recently_viewed_monitors.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_selector/use_recently_viewed_monitors.ts#:~:text=bulkResolve) | - | | <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SimpleSavedObject" text="SimpleSavedObject"/> | [synthetics_monitor.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/common/types/synthetics_monitor.ts#:~:text=SimpleSavedObject), [synthetics_monitor.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/common/types/synthetics_monitor.ts#:~:text=SimpleSavedObject), [synthetics_monitor.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/common/types/synthetics_monitor.ts#:~:text=SimpleSavedObject) | - | @@ -1272,7 +1268,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | <DocLink id="kibDataPluginApi" section="def-common.DataView.title" text="title"/> | [data_apis.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/common/lib/data_apis.ts#:~:text=title), [data_apis.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/common/lib/data_apis.ts#:~:text=title) | - | | <DocLink id="kibDataPluginApi" section="def-server.DataView.title" text="title"/> | [data_apis.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/common/lib/data_apis.ts#:~:text=title), [data_apis.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/common/lib/data_apis.ts#:~:text=title) | - | | <DocLink id="kibDataViewsPluginApi" section="def-public.DataView.title" text="title"/> | [data_apis.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/common/lib/data_apis.ts#:~:text=title) | - | -| <DocLink id="kibKbnCoreSavedObjectsCommonPluginApi" section="def-common.SavedObjectAttribute" text="SavedObjectAttribute"/> | [rule_reducer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_reducer.ts#:~:text=SavedObjectAttribute), [rule_reducer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_reducer.ts#:~:text=SavedObjectAttribute), [rule_reducer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_reducer.ts#:~:text=SavedObjectAttribute) | - | +| <DocLink id="kibKbnCoreSavedObjectsCommonPluginApi" section="def-common.SavedObjectAttribute" text="SavedObjectAttribute"/> | [rule_reducer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_reducer.ts#:~:text=SavedObjectAttribute), [rule_reducer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_reducer.ts#:~:text=SavedObjectAttribute), [rule_reducer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_reducer.ts#:~:text=SavedObjectAttribute), [rule_reducer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_reducer.ts#:~:text=SavedObjectAttribute) | - | @@ -1421,6 +1417,4 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| <DocLink id="kibLicensingPluginApi" section="def-public.LicensingPluginSetup.license$" text="license$"/> | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/watcher/public/plugin.ts#:~:text=license%24), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/watcher/public/plugin.ts#:~:text=license%24) | 8.8.0 | -| <DocLink id="kibKbnCoreLifecycleBrowserPluginApi" section="def-common.CoreStart.savedObjects" text="savedObjects"/> | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/watcher/public/plugin.ts#:~:text=savedObjects) | - | -| <DocLink id="kibKbnCoreSavedObjectsApiBrowserPluginApi" section="def-common.SavedObjectsClientContract" text="SavedObjectsClientContract"/> | [api.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/watcher/public/application/lib/api.ts#:~:text=SavedObjectsClientContract), [api.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/watcher/public/application/lib/api.ts#:~:text=SavedObjectsClientContract), [api.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/watcher/public/application/lib/api.ts#:~:text=SavedObjectsClientContract), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/watcher/public/application/index.tsx#:~:text=SavedObjectsClientContract), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/watcher/public/application/index.tsx#:~:text=SavedObjectsClientContract) | - | \ No newline at end of file +| <DocLink id="kibLicensingPluginApi" section="def-public.LicensingPluginSetup.license$" text="license$"/> | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/watcher/public/plugin.ts#:~:text=license%24), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/watcher/public/plugin.ts#:~:text=license%24) | 8.8.0 | \ No newline at end of file diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index e87a5fb863cf6..685bbdbec5153 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index 03393fafa70cd..9ac2b71ef357f 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: 2023-04-11 +date: 2023-04-12 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 e60eaff8d3a01..61aa5a32721fb 100644 --- a/api_docs/discover.devdocs.json +++ b/api_docs/discover.devdocs.json @@ -1202,10 +1202,6 @@ "plugin": "osquery", "path": "x-pack/plugins/osquery/public/common/hooks/use_discover_link.tsx" }, - { - "plugin": "synthetics", - "path": "x-pack/plugins/synthetics/public/legacy_uptime/components/synthetics/check_steps/stderr_logs.tsx" - }, { "plugin": "synthetics", "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/stderr_logs.tsx" diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index 28b6dcdcaa02d..410e59cf055e5 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: 2023-04-11 +date: 2023-04-12 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 c616324f0fee9..4f6a9521ba6b9 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/ecs_data_quality_dashboard.mdx b/api_docs/ecs_data_quality_dashboard.mdx index cdf42e20bd76a..872204bf6db85 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ecsDataQualityDashboard'] --- import ecsDataQualityDashboardObj from './ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index 434246002bba8..da5db41737d0d 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: 2023-04-11 +date: 2023-04-12 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 4191517d823c1..2b2e368e4642a 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: 2023-04-11 +date: 2023-04-12 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 762b5447dbf47..0bf6f0f0ba66f 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: 2023-04-11 +date: 2023-04-12 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 876c217670c41..d0dd726da9156 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: 2023-04-11 +date: 2023-04-12 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 d924605aef4e4..b7e6155233745 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index 9adaeaff4a986..9de177f87f62a 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index 1417474e3ffa4..0559f1e77f2d9 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: 2023-04-11 +date: 2023-04-12 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 cbe658adfd868..2e7f0195f9c77 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: 2023-04-11 +date: 2023-04-12 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 8d8b3fe18e40f..93ee8caffabf7 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: 2023-04-11 +date: 2023-04-12 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 f3a13864cf9bc..19691d76e7b93 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: 2023-04-11 +date: 2023-04-12 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 8e613a1dad33a..ccdaaf9da3b11 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: 2023-04-11 +date: 2023-04-12 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 0ee5212f967a4..de9c3c97e53af 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: 2023-04-11 +date: 2023-04-12 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 367352bdfdc49..1244ef5599da1 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: 2023-04-11 +date: 2023-04-12 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 66424980aaaf1..6dfc0a48c4d78 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: 2023-04-11 +date: 2023-04-12 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 8bd3a299448a7..8773538332bc4 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: 2023-04-11 +date: 2023-04-12 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 3c84716d8b65c..cac811a829cb4 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: 2023-04-11 +date: 2023-04-12 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 af725c6f8ee38..3bfb09b8256ff 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: 2023-04-11 +date: 2023-04-12 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 5fb2a78292e96..820ccf19b6d4b 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: 2023-04-11 +date: 2023-04-12 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 3a32afe277f69..8c0ff0f02fa5a 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: 2023-04-11 +date: 2023-04-12 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 3358698d7a3b2..e75bed35608bd 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: 2023-04-11 +date: 2023-04-12 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 d989daeb3648b..c85be89fa3018 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: 2023-04-11 +date: 2023-04-12 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 290fa6823c85d..d601fe1f3e45a 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: 2023-04-11 +date: 2023-04-12 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 1383c1b5b13d9..86b2219e74a72 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: 2023-04-11 +date: 2023-04-12 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 d9b9d55c20dcc..4ee2f95919f45 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index 6ed880f0897eb..0c7db90e87556 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: 2023-04-11 +date: 2023-04-12 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 918626a95292b..80f62cb35b744 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: 2023-04-11 +date: 2023-04-12 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 c8cdd1bc7d1e0..b17244a60d171 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'filesManagement'] --- import filesManagementObj from './files_management.devdocs.json'; diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 2f48c6dc14538..06cca89bc7a2f 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] --- import fleetObj from './fleet.devdocs.json'; diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index 173c56268f012..9641bbf5bc83c 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: 2023-04-11 +date: 2023-04-12 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 63fa0c8b66b73..d6fc11794daec 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: 2023-04-11 +date: 2023-04-12 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 37d9eae250b48..697cc91062e55 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: 2023-04-11 +date: 2023-04-12 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 4bc0dacda3932..7c4de0f990b9b 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: 2023-04-11 +date: 2023-04-12 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 91538459ccd43..8b3b214d0fd21 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: 2023-04-11 +date: 2023-04-12 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 50aa02ad9f43e..3692b258d53f0 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: 2023-04-11 +date: 2023-04-12 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 f007f0e0b1110..5d7f1b1e6a098 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index 28229106e1cef..056d90f82d11e 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index 0f5f7e7cf404a..58886be431073 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index 59c2f21ef47bd..6f0a7546acdfb 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.devdocs.json b/api_docs/kbn_aiops_components.devdocs.json index 04d030fd8fcee..10289c726ced6 100644 --- a/api_docs/kbn_aiops_components.devdocs.json +++ b/api_docs/kbn_aiops_components.devdocs.json @@ -93,7 +93,7 @@ "label": "ProgressControls", "description": [], "signature": [ - "({\n progress,\n progressMessage,\n onRefresh,\n onCancel,\n isRunning,\n shouldRerunAnalysis,\n}: ProgressControlProps) => JSX.Element" + "({ children, progress, progressMessage, onRefresh, onCancel, isRunning, shouldRerunAnalysis, }: React.PropsWithChildren<ProgressControlProps>) => JSX.Element" ], "path": "x-pack/packages/ml/aiops_components/src/progress_controls/progress_controls.tsx", "deprecated": false, @@ -102,12 +102,12 @@ { "parentPluginId": "@kbn/aiops-components", "id": "def-common.ProgressControls.$1", - "type": "Object", + "type": "CompoundType", "tags": [], - "label": "{\n progress,\n progressMessage,\n onRefresh,\n onCancel,\n isRunning,\n shouldRerunAnalysis,\n}", + "label": "{\n children,\n progress,\n progressMessage,\n onRefresh,\n onCancel,\n isRunning,\n shouldRerunAnalysis,\n}", "description": [], "signature": [ - "ProgressControlProps" + "React.PropsWithChildren<ProgressControlProps>" ], "path": "x-pack/packages/ml/aiops_components/src/progress_controls/progress_controls.tsx", "deprecated": false, diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index ff967350f62b4..e4ad2a8142546 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; diff --git a/api_docs/kbn_aiops_utils.mdx b/api_docs/kbn_aiops_utils.mdx index c7d0da238dda2..610ed26979d30 100644 --- a/api_docs/kbn_aiops_utils.mdx +++ b/api_docs/kbn_aiops_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-utils title: "@kbn/aiops-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-utils plugin -date: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-utils'] --- import kbnAiopsUtilsObj from './kbn_aiops_utils.devdocs.json'; diff --git a/api_docs/kbn_alerting_state_types.mdx b/api_docs/kbn_alerting_state_types.mdx index 2efd2d35a28c5..6253d82e3e091 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-state-types'] --- import kbnAlertingStateTypesObj from './kbn_alerting_state_types.devdocs.json'; diff --git a/api_docs/kbn_alerts.mdx b/api_docs/kbn_alerts.mdx index 7b1f7a0eb8e65..3c0cc45ecece3 100644 --- a/api_docs/kbn_alerts.mdx +++ b/api_docs/kbn_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts title: "@kbn/alerts" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts plugin -date: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts'] --- import kbnAlertsObj from './kbn_alerts.devdocs.json'; diff --git a/api_docs/kbn_alerts_as_data_utils.mdx b/api_docs/kbn_alerts_as_data_utils.mdx index ff868e29f9fc9..96353f411ed26 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: 2023-04-11 +date: 2023-04-12 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 f657f960e51e9..d9ee9415372bf 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: 2023-04-11 +date: 2023-04-12 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 e0fbec84c75a5..0f3f056fc60f3 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: 2023-04-11 +date: 2023-04-12 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 24722f2207699..1b7516055b21b 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-client'] --- import kbnAnalyticsClientObj from './kbn_analytics_client.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 c07575c024a31..331912de48adb 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: 2023-04-11 +date: 2023-04-12 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 691e043204ee4..f50b2d252ff35 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: 2023-04-11 +date: 2023-04-12 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 452ee54700b77..b4d2e41ee7c1d 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: 2023-04-11 +date: 2023-04-12 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 363d3ef01f412..9a00ea0acd411 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-fullstory'] --- import kbnAnalyticsShippersFullstoryObj from './kbn_analytics_shippers_fullstory.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_gainsight.mdx b/api_docs/kbn_analytics_shippers_gainsight.mdx index 6559bb788c02e..af34173e5d553 100644 --- a/api_docs/kbn_analytics_shippers_gainsight.mdx +++ b/api_docs/kbn_analytics_shippers_gainsight.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-gainsight title: "@kbn/analytics-shippers-gainsight" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-gainsight plugin -date: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-gainsight'] --- import kbnAnalyticsShippersGainsightObj from './kbn_analytics_shippers_gainsight.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index 2d5c44d5d045f..ef2f6fc19d76a 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: 2023-04-11 +date: 2023-04-12 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_synthtrace.mdx b/api_docs/kbn_apm_synthtrace.mdx index 2f64d23b9f90c..c2b98c4279b3e 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: 2023-04-11 +date: 2023-04-12 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.devdocs.json b/api_docs/kbn_apm_synthtrace_client.devdocs.json index 4aeb6fc81e78a..10dcb002bbdd0 100644 --- a/api_docs/kbn_apm_synthtrace_client.devdocs.json +++ b/api_docs/kbn_apm_synthtrace_client.devdocs.json @@ -2355,7 +2355,7 @@ "GeoLocation", "; 'client.geo.region_iso_code': string; 'client.geo.region_name': string; 'client.ip': string; 'cloud.account.id': string; 'cloud.account.name': string; 'cloud.availability_zone': string; 'cloud.machine.type': string; 'cloud.project.id': string; 'cloud.project.name': string; 'cloud.provider': string; 'cloud.region': string; 'cloud.service.name': string; 'container.id': string; 'destination.address': string; 'destination.port': number; 'device.id': string; 'device.manufacturer': string; 'device.model.identifier': string; 'device.model.name': string; 'ecs.version': string; 'error.exception': ", "ApmException", - "[]; 'error.grouping_key': string; 'error.grouping_name': string; 'error.id': string; 'event.ingested': number; 'event.name': string; 'event.outcome': string; 'event.outcome_numeric': number | { sum: number; value_count: number; }; 'faas.coldstart': boolean; 'faas.execution': string; 'faas.id': string; 'faas.name': string; 'faas.trigger.type': string; 'faas.version': string; 'host.architecture': string; 'host.hostname': string; 'host.name': string; 'host.os.full': string; 'host.os.name': string; 'host.os.platform': string; 'host.os.type': string; 'host.os.version': string; 'http.request.method': string; 'http.response.status_code': number; 'kubernetes.pod.name': string; 'kubernetes.pod.uid': string; 'labels.name': string; 'labels.telemetry_auto_version': string; 'metricset.name': string; 'network.carrier.icc': string; 'network.carrier.mcc': string; 'network.carrier.mnc': string; 'network.carrier.name': string; 'network.connection.subtype': string; 'network.connection.type': string; 'observer.type': string; 'observer.version_major': number; 'observer.version': string; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'session.id': string; 'trace.id': string; 'transaction.aggregation.overflow_count': number; 'transaction.duration.us': number; 'transaction.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'service.environment': string; 'service.framework.name': string; 'service.framework.version': string; 'service.language.name': string; 'service.language.version': string; 'service.name': string; 'service.node.name': string; 'service.runtime.name': string; 'service.runtime.version': string; 'service.target.name': string; 'service.target.type': string; 'service.version': string; 'span.action': string; 'span.destination.service.resource': string; 'span.destination.service.response_time.count': number; 'span.destination.service.response_time.sum.us': number; 'span.duration.us': number; 'span.id': string; 'span.name': string; 'span.self_time.count': number; 'span.self_time.sum.us': number; 'span.subtype': string; 'span.type': string; 'transaction.result': string; 'transaction.sampled': true; 'span.links': { trace: { id: string; }; span: { id: string; }; }[]; 'url.original': string; }> & Partial<{ 'system.process.memory.size': number; 'system.memory.actual.free': number; 'system.memory.total': number; 'system.cpu.total.norm.pct': number; 'system.process.memory.rss.bytes': number; 'system.process.cpu.total.norm.pct': number; 'jvm.memory.heap.used': number; 'jvm.memory.non_heap.used': number; 'jvm.thread.count': number; 'faas.billed_duration': number; 'faas.timeout': number; 'faas.coldstart_duration': number; 'faas.duration': number; }> & Partial<{ 'metricset.interval': string; 'transaction.duration.summary': string; }>" + "[]; 'error.grouping_key': string; 'error.grouping_name': string; 'error.id': string; 'event.ingested': number; 'event.name': string; 'event.outcome': string; 'event.outcome_numeric': number | { sum: number; value_count: number; }; 'faas.coldstart': boolean; 'faas.execution': string; 'faas.id': string; 'faas.name': string; 'faas.trigger.type': string; 'faas.version': string; 'host.architecture': string; 'host.hostname': string; 'host.name': string; 'host.os.full': string; 'host.os.name': string; 'host.os.platform': string; 'host.os.type': string; 'host.os.version': string; 'http.request.method': string; 'http.response.status_code': number; 'kubernetes.pod.name': string; 'kubernetes.pod.uid': string; 'labels.name': string; 'labels.telemetry_auto_version': string; 'metricset.name': string; 'network.carrier.icc': string; 'network.carrier.mcc': string; 'network.carrier.mnc': string; 'network.carrier.name': string; 'network.connection.subtype': string; 'network.connection.type': string; 'observer.type': string; 'observer.version_major': number; 'observer.version': string; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'session.id': string; 'trace.id': string; 'transaction.aggregation.overflow_count': number; 'transaction.duration.us': number; 'transaction.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.result': string; 'transaction.sampled': boolean; 'service.environment': string; 'service.framework.name': string; 'service.framework.version': string; 'service.language.name': string; 'service.language.version': string; 'service.name': string; 'service.node.name': string; 'service.runtime.name': string; 'service.runtime.version': string; 'service.target.name': string; 'service.target.type': string; 'service.version': string; 'span.action': string; 'span.destination.service.resource': string; 'span.destination.service.response_time.count': number; 'span.destination.service.response_time.sum.us': number; 'span.duration.us': number; 'span.id': string; 'span.name': string; 'span.self_time.count': number; 'span.self_time.sum.us': number; 'span.subtype': string; 'span.type': string; 'span.links': { trace: { id: string; }; span: { id: string; }; }[]; 'url.original': string; }> & Partial<{ 'system.process.memory.size': number; 'system.memory.actual.free': number; 'system.memory.total': number; 'system.cpu.total.norm.pct': number; 'system.process.memory.rss.bytes': number; 'system.process.cpu.total.norm.pct': number; 'jvm.memory.heap.used': number; 'jvm.memory.non_heap.used': number; 'jvm.thread.count': number; 'faas.billed_duration': number; 'faas.timeout': number; 'faas.coldstart_duration': number; 'faas.duration': number; }> & Partial<{ 'metricset.interval': string; 'transaction.duration.summary': string; }>" ], "path": "packages/kbn-apm-synthtrace-client/src/lib/apm/apm_fields.ts", "deprecated": false, diff --git a/api_docs/kbn_apm_synthtrace_client.mdx b/api_docs/kbn_apm_synthtrace_client.mdx index 5080ea83c6c4f..277035410c526 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: 2023-04-11 +date: 2023-04-12 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 fd351638468db..eb7cebcad9489 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: 2023-04-11 +date: 2023-04-12 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 28b6ec40ef05e..cf86084e3ac44 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_cases_components.mdx b/api_docs/kbn_cases_components.mdx index 9ee3317f316c4..49d4246a87a7e 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: 2023-04-11 +date: 2023-04-12 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 42f55579aeaca..fdea15198ef3b 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: 2023-04-11 +date: 2023-04-12 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 6f47cfd32bd16..e639c29f94a3d 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: 2023-04-11 +date: 2023-04-12 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 952e0d11b51ca..80c86969f055f 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: 2023-04-11 +date: 2023-04-12 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 ceecce62b661e..0c2aaa2d1dc3b 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: 2023-04-11 +date: 2023-04-12 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 5a0299745b5a6..ad5d0e97b7262 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: 2023-04-11 +date: 2023-04-12 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 c366f6866aa2b..3fe5f79ca836f 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: 2023-04-11 +date: 2023-04-12 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 7c1794e87ff2f..de11259a11079 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: 2023-04-11 +date: 2023-04-12 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 a11dca05e6436..7e8f0caf9e9cd 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor'] --- import kbnCodeEditorObj from './kbn_code_editor.devdocs.json'; diff --git a/api_docs/kbn_code_editor_mocks.mdx b/api_docs/kbn_code_editor_mocks.mdx index 75282bb3c07b7..b530a128bac27 100644 --- a/api_docs/kbn_code_editor_mocks.mdx +++ b/api_docs/kbn_code_editor_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor-mocks title: "@kbn/code-editor-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor-mocks plugin -date: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor-mocks'] --- import kbnCodeEditorMocksObj from './kbn_code_editor_mocks.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index 28083caf49ffb..8e938a53e5698 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: 2023-04-11 +date: 2023-04-12 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 be347005f5c37..a66516391e162 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: 2023-04-11 +date: 2023-04-12 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 096fd681f2bfb..b7e3f7c2b6d4a 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: 2023-04-11 +date: 2023-04-12 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 77ecdb20967d8..b722cf327dab1 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: 2023-04-11 +date: 2023-04-12 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 8fb39053da61c..3d54306433533 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: 2023-04-11 +date: 2023-04-12 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_table_list.mdx b/api_docs/kbn_content_management_table_list.mdx index 5e19af5bd2f1a..9b2d8f38adcaf 100644 --- a/api_docs/kbn_content_management_table_list.mdx +++ b/api_docs/kbn_content_management_table_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list title: "@kbn/content-management-table-list" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list plugin -date: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list'] --- import kbnContentManagementTableListObj from './kbn_content_management_table_list.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index 2dfc571e80bcd..c1eaeb1c84b19 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: 2023-04-11 +date: 2023-04-12 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 6eadd2670a220..a5de43b83b1fb 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: 2023-04-11 +date: 2023-04-12 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 57ce9e978979a..023a80a62be47 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: 2023-04-11 +date: 2023-04-12 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 3ddd221198875..538e4bcf88d6f 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: 2023-04-11 +date: 2023-04-12 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 a8e2b398599f4..f81bab0d0ebe9 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: 2023-04-11 +date: 2023-04-12 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 d9a00db9b4a57..7085922914375 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: 2023-04-11 +date: 2023-04-12 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 36aecc47c83da..b2f06a0267daf 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: 2023-04-11 +date: 2023-04-12 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 6424aa6b85e28..994c0e548e6fa 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: 2023-04-11 +date: 2023-04-12 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 e7501f7ff53cb..0d13e7861ae72 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: 2023-04-11 +date: 2023-04-12 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 88681ba9dfee3..03a1742f47dd0 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: 2023-04-11 +date: 2023-04-12 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 dc8070e8c249d..c04a8bf8db432 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: 2023-04-11 +date: 2023-04-12 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 7b98c555b772c..16f51923f0b86 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: 2023-04-11 +date: 2023-04-12 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 6e30baa890bb8..6bdeb16ab85cd 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: 2023-04-11 +date: 2023-04-12 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 bd87d76dde44f..9d42962260e84 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: 2023-04-11 +date: 2023-04-12 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 d8dafde600a3c..8d39574092ed3 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: 2023-04-11 +date: 2023-04-12 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 ffeccf0deea16..487e24edeb1ff 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: 2023-04-11 +date: 2023-04-12 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 dd982aae818c2..b96351e1cd05c 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: 2023-04-11 +date: 2023-04-12 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 e698100260bac..7a5f8d8dc1dc9 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: 2023-04-11 +date: 2023-04-12 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 11b1d49546557..745eca37a4f84 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: 2023-04-11 +date: 2023-04-12 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 dd72fe5fdf9e5..9fb53fe92479f 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: 2023-04-11 +date: 2023-04-12 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 ec990b1787241..a346158f28841 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: 2023-04-11 +date: 2023-04-12 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 77cb03a120914..200b0c83d1102 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: 2023-04-11 +date: 2023-04-12 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 d75a2d8794b36..fc961a390ecac 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: 2023-04-11 +date: 2023-04-12 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 9865a643beaa8..5787c17fea0ad 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: 2023-04-11 +date: 2023-04-12 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 81667cd4e8bf6..7c349bed9d131 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: 2023-04-11 +date: 2023-04-12 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 28eaa37d1cb11..e3a4c46a5e64f 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: 2023-04-11 +date: 2023-04-12 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 8260177cf5abd..0195a56fb9af2 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: 2023-04-11 +date: 2023-04-12 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 103a9e08e1e0b..1d0ccff6eb10a 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: 2023-04-11 +date: 2023-04-12 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 b449abd2c1018..d52b8311e5b0f 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: 2023-04-11 +date: 2023-04-12 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 60c679fff0e66..8374609c8c8ba 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: 2023-04-11 +date: 2023-04-12 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 ead28afe6f426..3965e6bb6cb32 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: 2023-04-11 +date: 2023-04-12 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 70dc66c8bcf1a..ec15f2a338f2d 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: 2023-04-11 +date: 2023-04-12 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 02fcb41c7a37a..515fa5acce7b8 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: 2023-04-11 +date: 2023-04-12 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 6e9fcdd61af99..34d39c2666e3c 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: 2023-04-11 +date: 2023-04-12 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 5b45decb1a9cd..5e148b849d119 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: 2023-04-11 +date: 2023-04-12 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 186618e369721..6c932e1f801e3 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: 2023-04-11 +date: 2023-04-12 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 9b9656b7d097f..31b8dda8b5242 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: 2023-04-11 +date: 2023-04-12 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 4f71d57eafae1..7cbe4b8b085c1 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: 2023-04-11 +date: 2023-04-12 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 2b6542641ec22..291c4d60c0c78 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: 2023-04-11 +date: 2023-04-12 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 d27934f3927e6..c386cdaf20f06 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: 2023-04-11 +date: 2023-04-12 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 a4b602b008821..7e5a6dd3a9454 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: 2023-04-11 +date: 2023-04-12 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 df62509bb915a..07bc6555b842e 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: 2023-04-11 +date: 2023-04-12 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 e8875a0ae95e4..1b931ade46ada 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: 2023-04-11 +date: 2023-04-12 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 b6e438b468602..0f8e3c8b0215c 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: 2023-04-11 +date: 2023-04-12 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 84be11d8ba1e7..8cba04aa84686 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: 2023-04-11 +date: 2023-04-12 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 89faa42b6990a..9bd0add2159c1 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: 2023-04-11 +date: 2023-04-12 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 2988c79456e12..eb247a3eedd54 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: 2023-04-11 +date: 2023-04-12 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 6fa6da3025f34..34a4439a815d8 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: 2023-04-11 +date: 2023-04-12 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 7277e55bc4b3b..6c5badb4ed826 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: 2023-04-11 +date: 2023-04-12 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 5064d51b5312d..a19b9ac1ac68a 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: 2023-04-11 +date: 2023-04-12 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 e771406b6047c..56a90bbb98bfc 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: 2023-04-11 +date: 2023-04-12 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 b61f5282c349f..20ea903e746e2 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: 2023-04-11 +date: 2023-04-12 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 dd35b4b734fd0..bb7ad46dac1bd 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: 2023-04-11 +date: 2023-04-12 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 ba56d94cffc55..1b20d2bdde362 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: 2023-04-11 +date: 2023-04-12 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 907a5fc1dd5fd..eb8ed8e2260ee 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: 2023-04-11 +date: 2023-04-12 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 e407cbc373472..3670ccfdcc859 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: 2023-04-11 +date: 2023-04-12 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 0ae4aa95c1083..4691997a82712 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: 2023-04-11 +date: 2023-04-12 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 021ea35d8def5..c0026a2110da4 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: 2023-04-11 +date: 2023-04-12 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 c68a6ca72799a..5c7bbe0a481e1 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: 2023-04-11 +date: 2023-04-12 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 6eea5bc049c02..1be1b292591c2 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: 2023-04-11 +date: 2023-04-12 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 72ba521531a66..31b3046d26e91 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: 2023-04-11 +date: 2023-04-12 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 dc9d6f54478ec..71a6aa55c4ea2 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: 2023-04-11 +date: 2023-04-12 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 b6573c31fe9ba..2d2001539df12 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: 2023-04-11 +date: 2023-04-12 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 a83180458c103..25622b8801a8f 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: 2023-04-11 +date: 2023-04-12 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 4f56ec866d8f0..bd239da9027bf 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: 2023-04-11 +date: 2023-04-12 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 90c614a08c2ba..8c33d682a1f74 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: 2023-04-11 +date: 2023-04-12 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 36b449cce6bec..69cdba3ff2c73 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: 2023-04-11 +date: 2023-04-12 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 d1600e9c85fe2..1feb8b9ec27ac 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: 2023-04-11 +date: 2023-04-12 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 492cd62a4169e..68805d084c0c4 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: 2023-04-11 +date: 2023-04-12 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 d5d1b8090485b..9179abbd6df4e 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: 2023-04-11 +date: 2023-04-12 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 d9af0d0e73e3c..dc4cec249c440 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: 2023-04-11 +date: 2023-04-12 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 3930a3f2c7074..cbcff991f8dd0 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: 2023-04-11 +date: 2023-04-12 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 30741ef89d495..e5d1566e9dc71 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: 2023-04-11 +date: 2023-04-12 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 f782e9ea15fc8..3e4813fbc4f5b 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: 2023-04-11 +date: 2023-04-12 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 4528636640e42..e3df62b55d60e 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: 2023-04-11 +date: 2023-04-12 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 6c91d9da0914e..a9c5977343b0e 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: 2023-04-11 +date: 2023-04-12 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 3096f5706caa9..b44b7df7da864 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: 2023-04-11 +date: 2023-04-12 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 63a5e2a3fe87f..dfb3eb4bbdb30 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: 2023-04-11 +date: 2023-04-12 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 9241ed18a0d13..1c792dba888ab 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: 2023-04-11 +date: 2023-04-12 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 f22036d9fe6f1..0dbd20cca0b89 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: 2023-04-11 +date: 2023-04-12 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 fa4c32568aba3..76b224bf54d29 100644 --- a/api_docs/kbn_core_lifecycle_browser.devdocs.json +++ b/api_docs/kbn_core_lifecycle_browser.devdocs.json @@ -769,22 +769,6 @@ "plugin": "synthetics", "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/monitor_filters/use_filters.ts" }, - { - "plugin": "synthetics", - "path": "x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/monitor_config/use_monitor_name.ts" - }, - { - "plugin": "synthetics", - "path": "x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/manage_locations/hooks/use_location_monitors.ts" - }, - { - "plugin": "synthetics", - "path": "x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/manage_locations/hooks/use_locations_api.ts" - }, - { - "plugin": "synthetics", - "path": "x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/hooks/use_invalid_monitors.tsx" - }, { "plugin": "synthetics", "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_selector/use_recently_viewed_monitors.ts" @@ -809,10 +793,6 @@ "plugin": "transform", "path": "x-pack/plugins/transform/public/app/mount_management_section.ts" }, - { - "plugin": "watcher", - "path": "x-pack/plugins/watcher/public/plugin.ts" - }, { "plugin": "@kbn/core-plugins-browser-internal", "path": "packages/core/plugins/core-plugins-browser-internal/src/plugins_service.test.ts" @@ -844,14 +824,6 @@ { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/index.tsx" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/use_create_security_dashboard_link.ts" } ] }, diff --git a/api_docs/kbn_core_lifecycle_browser.mdx b/api_docs/kbn_core_lifecycle_browser.mdx index 482742fe74228..37b40d63532d8 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: 2023-04-11 +date: 2023-04-12 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 f55621252ac7b..c6a5be120d834 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: 2023-04-11 +date: 2023-04-12 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 307e37b4484da..9fa5a959a7506 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: 2023-04-11 +date: 2023-04-12 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 211903ff3bdd7..2c3ebb4b4c574 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: 2023-04-11 +date: 2023-04-12 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 ab54c34d8b5e3..89301d73a6d00 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: 2023-04-11 +date: 2023-04-12 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 d803d19134642..7978465c23baa 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: 2023-04-11 +date: 2023-04-12 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 dc5fae734cdd1..b79f18daffb1b 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: 2023-04-11 +date: 2023-04-12 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 8c65c5c25c432..adecb6ba08bb5 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: 2023-04-11 +date: 2023-04-12 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 0a85e2b3100f5..d2fe2c84c067b 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: 2023-04-11 +date: 2023-04-12 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 3d20a1095a77f..f0b2076cb7d1f 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: 2023-04-11 +date: 2023-04-12 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 8139952bf2144..98f52053311cf 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: 2023-04-11 +date: 2023-04-12 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 159b9d51be93a..9c2a295fcf02f 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: 2023-04-11 +date: 2023-04-12 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 b20a89fc0b555..c18779e0da5b8 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: 2023-04-11 +date: 2023-04-12 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 4ef1373468cee..6711e717f4d53 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: 2023-04-11 +date: 2023-04-12 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 30a542ae1da9a..f27755fb1a319 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: 2023-04-11 +date: 2023-04-12 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 412a86bf97ac4..9f0fa5302062f 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: 2023-04-11 +date: 2023-04-12 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 c6b160ea19e75..b25ce7f6300e7 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: 2023-04-11 +date: 2023-04-12 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 22e688bdef9de..71f1ddfd6ce8a 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: 2023-04-11 +date: 2023-04-12 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 8802c3d3861d3..f9a855a86737c 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: 2023-04-11 +date: 2023-04-12 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 cf3cc0c086998..51be36555967a 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: 2023-04-11 +date: 2023-04-12 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 5530eab5cb83a..c8127f957f6df 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: 2023-04-11 +date: 2023-04-12 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 a7ec0b81aacdd..d5b75a439ffdb 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: 2023-04-11 +date: 2023-04-12 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 7cf025e32598a..85d6ab2220507 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: 2023-04-11 +date: 2023-04-12 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 28d51b8d6d86a..d5d0501a26754 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: 2023-04-11 +date: 2023-04-12 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 7ee6e7f610172..8d832565dcead 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: 2023-04-11 +date: 2023-04-12 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 6bdda210dd6ad..987055898b287 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: 2023-04-11 +date: 2023-04-12 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_server.mdx b/api_docs/kbn_core_plugins_server.mdx index dea9383bc3e0e..6ecf1a8222af0 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: 2023-04-11 +date: 2023-04-12 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 aee38a3b7e7e0..8e5e990df2783 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: 2023-04-11 +date: 2023-04-12 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 eae07669610b4..9ff585c9b04ec 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: 2023-04-11 +date: 2023-04-12 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 b195ed1fd79ac..a88a90766c2a6 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: 2023-04-11 +date: 2023-04-12 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 e33b7102cc26a..6dd0607186e20 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: 2023-04-11 +date: 2023-04-12 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 610ed2cb438da..6512de2070b25 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: 2023-04-11 +date: 2023-04-12 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 f9d3df7f0d056..8a1104debdceb 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: 2023-04-11 +date: 2023-04-12 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 c2c0a9f479bb5..987493c4ea9a6 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: 2023-04-11 +date: 2023-04-12 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.devdocs.json b/api_docs/kbn_core_saved_objects_api_browser.devdocs.json index 2de842b19eca3..1782399f2118f 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.devdocs.json +++ b/api_docs/kbn_core_saved_objects_api_browser.devdocs.json @@ -1266,50 +1266,6 @@ "plugin": "graph", "path": "x-pack/plugins/graph/public/application.tsx" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts" - }, - { - "plugin": "synthetics", - "path": "x-pack/plugins/synthetics/public/legacy_uptime/state/private_locations/api.ts" - }, - { - "plugin": "synthetics", - "path": "x-pack/plugins/synthetics/public/legacy_uptime/state/private_locations/api.ts" - }, - { - "plugin": "synthetics", - "path": "x-pack/plugins/synthetics/public/legacy_uptime/state/private_locations/api.ts" - }, - { - "plugin": "watcher", - "path": "x-pack/plugins/watcher/public/application/lib/api.ts" - }, - { - "plugin": "watcher", - "path": "x-pack/plugins/watcher/public/application/lib/api.ts" - }, - { - "plugin": "watcher", - "path": "x-pack/plugins/watcher/public/application/lib/api.ts" - }, - { - "plugin": "watcher", - "path": "x-pack/plugins/watcher/public/application/index.tsx" - }, - { - "plugin": "watcher", - "path": "x-pack/plugins/watcher/public/application/index.tsx" - }, { "plugin": "graph", "path": "x-pack/plugins/graph/public/state_management/mocks.ts" @@ -1338,14 +1294,6 @@ "plugin": "lens", "path": "x-pack/plugins/lens/public/persistence/saved_objects_utils/find_object_by_title.test.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/utils.test.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/utils.test.ts" - }, { "plugin": "visualizations", "path": "src/plugins/visualizations/public/utils/saved_visualize_utils.test.ts" @@ -1546,10 +1494,6 @@ "plugin": "graph", "path": "x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts" }, - { - "plugin": "synthetics", - "path": "x-pack/plugins/synthetics/public/legacy_uptime/state/private_locations/api.ts" - }, { "plugin": "graph", "path": "x-pack/plugins/graph/public/helpers/saved_workspace_utils.test.ts" @@ -2279,26 +2223,10 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/index.tsx" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts" - }, { "plugin": "synthetics", "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/monitor_filters/use_filters.ts" }, - { - "plugin": "synthetics", - "path": "x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/monitor_config/use_monitor_name.ts" - }, - { - "plugin": "synthetics", - "path": "x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/manage_locations/hooks/use_location_monitors.ts" - }, { "plugin": "synthetics", "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/settings/private_locations/hooks/use_location_monitors.ts" @@ -2507,10 +2435,6 @@ "plugin": "monitoring", "path": "x-pack/plugins/monitoring/public/application/pages/elasticsearch/ingest_pipeline_modal.tsx" }, - { - "plugin": "synthetics", - "path": "x-pack/plugins/synthetics/public/legacy_uptime/state/private_locations/api.ts" - }, { "plugin": "savedObjects", "path": "src/plugins/saved_objects/public/saved_object/saved_object.test.ts" @@ -2952,10 +2876,6 @@ "plugin": "fleet", "path": "x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/assets/assets.tsx" }, - { - "plugin": "synthetics", - "path": "x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/hooks/use_invalid_monitors.tsx" - }, { "plugin": "synthetics", "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_selector/use_recently_viewed_monitors.ts" diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index 3ae0936c931b3..422d0528b666d 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: 2023-04-11 +date: 2023-04-12 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 1f0fb50643532..d0e2693424e29 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: 2023-04-11 +date: 2023-04-12 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_internal.mdx b/api_docs/kbn_core_saved_objects_api_server_internal.mdx index ac00073776f28..fe90bd18f5a27 100644 --- a/api_docs/kbn_core_saved_objects_api_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-internal title: "@kbn/core-saved-objects-api-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-internal plugin -date: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server-internal'] --- import kbnCoreSavedObjectsApiServerInternalObj from './kbn_core_saved_objects_api_server_internal.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 462c86bd61213..1e05f854ef279 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: 2023-04-11 +date: 2023-04-12 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 fa187f83374c5..c0db75fdc64e7 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: 2023-04-11 +date: 2023-04-12 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 14fcc00a77399..291369d75b975 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: 2023-04-11 +date: 2023-04-12 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 e2b1898b240b1..7e4095440c31f 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: 2023-04-11 +date: 2023-04-12 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 d452e32fa75ca..1e7007a9313c8 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: 2023-04-11 +date: 2023-04-12 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 55876d53c34ef..2de1aede3738d 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: 2023-04-11 +date: 2023-04-12 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.devdocs.json b/api_docs/kbn_core_saved_objects_common.devdocs.json index d07a7c9e99278..8ede2d77bb796 100644 --- a/api_docs/kbn_core_saved_objects_common.devdocs.json +++ b/api_docs/kbn_core_saved_objects_common.devdocs.json @@ -1399,22 +1399,6 @@ "plugin": "osquery", "path": "x-pack/plugins/osquery/public/assets/use_assets_status.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/utils.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/containers/dashboards/use_security_dashboards_table.tsx" - }, { "plugin": "synthetics", "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/monitor_detail_flyout.tsx" @@ -1885,6 +1869,10 @@ "plugin": "triggersActionsUi", "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_reducer.ts" }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_reducer.ts" + }, { "plugin": "visualizations", "path": "src/plugins/visualizations/public/utils/saved_visualization_references/saved_visualization_references.ts" diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index 281b8fa7d787a..9a18639cd5bb9 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: 2023-04-11 +date: 2023-04-12 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 06813e3aca376..d260b95bf9c82 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: 2023-04-11 +date: 2023-04-12 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 2b466c4367785..a930694846aae 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: 2023-04-11 +date: 2023-04-12 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 b766015f8e760..3d494d4a03232 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: 2023-04-11 +date: 2023-04-12 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 59bb4bbe0ac56..c87ee74b3c04e 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: 2023-04-11 +date: 2023-04-12 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 65eab2292b6ac..e7e9eca4b7f1f 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: 2023-04-11 +date: 2023-04-12 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 4cbc048d91d1d..b796438572ca9 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: 2023-04-11 +date: 2023-04-12 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 59ab4d19001e0..80643f3759c2b 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: 2023-04-11 +date: 2023-04-12 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 5e08163b4f9aa..6c9c3fbd8d672 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: 2023-04-11 +date: 2023-04-12 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_status_common.mdx b/api_docs/kbn_core_status_common.mdx index 5df25dab6da39..26ead8a8c8c65 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: 2023-04-11 +date: 2023-04-12 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 e6eaaca7c8b56..07ee1190b549e 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: 2023-04-11 +date: 2023-04-12 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 8265b5f33c7b4..377d6051cc4c8 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: 2023-04-11 +date: 2023-04-12 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 fe47f5148a4fc..29f12ca7baa24 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: 2023-04-11 +date: 2023-04-12 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 86a32fd544260..454455c7a66e8 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: 2023-04-11 +date: 2023-04-12 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 cef1db1af7993..f918b8fbe06ae 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: 2023-04-11 +date: 2023-04-12 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 1f4f6a2ad8931..3de43586fc1cc 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: 2023-04-11 +date: 2023-04-12 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 7efb08c613080..b63b0ddfd8e07 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: 2023-04-11 +date: 2023-04-12 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_so_type_serializer.mdx b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx index a80fd295bde00..31ee2c2c35194 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: 2023-04-11 +date: 2023-04-12 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 a93cae2dd9b97..df2e57f761a8a 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: 2023-04-11 +date: 2023-04-12 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 b390ead27f714..4de4d96963c78 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: 2023-04-11 +date: 2023-04-12 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_internal.mdx b/api_docs/kbn_core_theme_browser_internal.mdx index d86faf1a1438f..977481dfddca9 100644 --- a/api_docs/kbn_core_theme_browser_internal.mdx +++ b/api_docs/kbn_core_theme_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-internal title: "@kbn/core-theme-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-internal plugin -date: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-internal'] --- import kbnCoreThemeBrowserInternalObj from './kbn_core_theme_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index 464d88614622c..62f32a6008ace 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: 2023-04-11 +date: 2023-04-12 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 1f085c339761e..1b9f4b17ab9cb 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: 2023-04-11 +date: 2023-04-12 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 eb33470a395e6..a3e69b5725c87 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: 2023-04-11 +date: 2023-04-12 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 9a2a3ab2689ab..8fcf9a15e9e1a 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: 2023-04-11 +date: 2023-04-12 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 9c5c34f468e3a..dca31d85f034c 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: 2023-04-11 +date: 2023-04-12 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 733355975e2b8..537a48887ac09 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: 2023-04-11 +date: 2023-04-12 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 1e0204a5219c7..1f37e6980d7fe 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: 2023-04-11 +date: 2023-04-12 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 9f65cc01ada7b..973d5cdd34bd0 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: 2023-04-11 +date: 2023-04-12 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 a02d48af21748..1e3eec5b8b6c5 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: 2023-04-11 +date: 2023-04-12 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 fdb56e89b04a5..239c6d96462a4 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: 2023-04-11 +date: 2023-04-12 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 5f2a25adc8838..d8c379b259146 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: 2023-04-11 +date: 2023-04-12 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_crypto.mdx b/api_docs/kbn_crypto.mdx index ff5911d10d9ea..0394cfe73aca5 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: 2023-04-11 +date: 2023-04-12 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 f74e4a237106a..ea42a576fe201 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_cypress_config.mdx b/api_docs/kbn_cypress_config.mdx index b45df2134c921..2f66308315c6b 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cypress-config'] --- import kbnCypressConfigObj from './kbn_cypress_config.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index abf7546877f01..bd9eab81a5c4c 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index 41dd181c49791..167436ebba368 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: 2023-04-11 +date: 2023-04-12 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 e555a06f48d3c..3b34653a05740 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: 2023-04-11 +date: 2023-04-12 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 55ad08127f44c..b53e67774de3a 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: 2023-04-11 +date: 2023-04-12 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 b14a41a365e71..e5b73b75f4469 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.devdocs.json b/api_docs/kbn_doc_links.devdocs.json index e00902df93b87..de25c4c41b47d 100644 --- a/api_docs/kbn_doc_links.devdocs.json +++ b/api_docs/kbn_doc_links.devdocs.json @@ -300,7 +300,7 @@ "label": "enterpriseSearch", "description": [], "signature": [ - "{ readonly apiKeys: string; readonly behavioralAnalytics: string; readonly behavioralAnalyticsEvents: string; readonly bulkApi: string; readonly configuration: string; readonly connectors: string; readonly connectorsMongoDB: string; readonly connectorsMySQL: string; readonly connectorsWorkplaceSearch: string; readonly crawlerExtractionRules: string; readonly crawlerManaging: string; readonly crawlerOverview: string; readonly deployTrainedModels: string; readonly documentLevelSecurity: string; readonly engines: string; readonly ingestPipelines: string; readonly languageAnalyzers: string; readonly languageClients: string; readonly licenseManagement: string; readonly machineLearningStart: string; readonly mailService: string; readonly start: string; readonly syncRules: string; readonly troubleshootSetup: string; readonly usersAccess: string; }" + "{ readonly apiKeys: string; readonly behavioralAnalytics: string; readonly behavioralAnalyticsEvents: string; readonly bulkApi: string; readonly configuration: string; readonly connectors: string; readonly connectorsMongoDB: string; readonly connectorsMySQL: string; readonly connectorsWorkplaceSearch: string; readonly crawlerExtractionRules: string; readonly crawlerManaging: string; readonly crawlerOverview: string; readonly deployTrainedModels: string; readonly documentLevelSecurity: string; readonly elser: string; readonly engines: string; readonly ingestPipelines: string; readonly languageAnalyzers: string; readonly languageClients: string; readonly licenseManagement: string; readonly machineLearningStart: string; readonly mailService: string; readonly start: string; readonly syncRules: string; readonly troubleshootSetup: string; readonly usersAccess: 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 bd2627a2484fa..aa80f93ca8561 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: 2023-04-11 +date: 2023-04-12 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 675e6a448dded..d0361d29b758b 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: 2023-04-11 +date: 2023-04-12 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 076905608f0e9..55dabda6e17c7 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: 2023-04-11 +date: 2023-04-12 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 5cc38a66e0221..b3230e22b6abc 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_ecs.mdx b/api_docs/kbn_ecs.mdx index 54b2682e3dad5..5b8d8afd9c89b 100644 --- a/api_docs/kbn_ecs.mdx +++ b/api_docs/kbn_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs title: "@kbn/ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs plugin -date: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs'] --- import kbnEcsObj from './kbn_ecs.devdocs.json'; diff --git a/api_docs/kbn_ecs_data_quality_dashboard.mdx b/api_docs/kbn_ecs_data_quality_dashboard.mdx index 620942a7a901b..d266e0937d598 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: 2023-04-11 +date: 2023-04-12 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_es.mdx b/api_docs/kbn_es.mdx index c3b910f860fd7..e2237c6947bd3 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: 2023-04-11 +date: 2023-04-12 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 b62273625beaa..db27555f1aa14 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: 2023-04-11 +date: 2023-04-12 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 f2182b67f95d3..3363af7ade653 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: 2023-04-11 +date: 2023-04-12 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 9bd7d14322554..6073727aff748 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: 2023-04-11 +date: 2023-04-12 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 58fc06f3518c5..25e331e2ea51c 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: 2023-04-11 +date: 2023-04-12 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 0e858642adb89..2d22483325204 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_expandable_flyout.mdx b/api_docs/kbn_expandable_flyout.mdx index ff92135145721..1f60a294ba715 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: 2023-04-11 +date: 2023-04-12 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 cf2b11c7fb243..d1f018baeee4f 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index 8139b7ef1ac23..be844ef174524 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: 2023-04-11 +date: 2023-04-12 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_ftr_common_functional_services.mdx b/api_docs/kbn_ftr_common_functional_services.mdx index 6552b451cb512..6bdaa162e4af3 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: 2023-04-11 +date: 2023-04-12 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_generate.mdx b/api_docs/kbn_generate.mdx index 513001ddaab71..3863130d714f4 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index e7a537fa54955..fc9d839c9cb54 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: 2023-04-11 +date: 2023-04-12 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 4c5622ed3ccc2..ac995c1f66ab2 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: 2023-04-11 +date: 2023-04-12 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 96ddb25c7a5f0..2c5500fe4b113 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: 2023-04-11 +date: 2023-04-12 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 b630a9542f310..242d0a822363d 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: 2023-04-11 +date: 2023-04-12 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 a95a3e93ae2e3..18326306f2ade 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: 2023-04-11 +date: 2023-04-12 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 66579dd5a15b0..12ae8a8fd7a09 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: 2023-04-11 +date: 2023-04-12 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 4dbb3c95e2ad6..f2c010e767a74 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: 2023-04-11 +date: 2023-04-12 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 ad5f189909751..b23cc7a8d4b87 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: 2023-04-11 +date: 2023-04-12 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 edfe948205b23..f836f4c1149c7 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index 18d2c5b517a83..5637a9c859f10 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: 2023-04-11 +date: 2023-04-12 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 44dd2aa8c1530..2f7cf83e6c4c0 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] --- import kbnIoTsUtilsObj from './kbn_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index 908da825549d5..a2f333adb1a04 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: 2023-04-11 +date: 2023-04-12 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 5d10b4d50d0f7..c64845325ce6f 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: 2023-04-11 +date: 2023-04-12 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 87c92d492db5f..63e4a975c87ba 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: 2023-04-11 +date: 2023-04-12 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 c3d67ba5360f6..0912abd79f3f0 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: 2023-04-11 +date: 2023-04-12 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 c7d9b0bf10f22..57cffe700b465 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/language-documentation-popover'] --- import kbnLanguageDocumentationPopoverObj from './kbn_language_documentation_popover.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index 80e48ac9d150f..18fef97b05c1f 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: 2023-04-11 +date: 2023-04-12 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 1839877dba21d..5edd67c641535 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] --- import kbnLoggingMocksObj from './kbn_logging_mocks.devdocs.json'; diff --git a/api_docs/kbn_managed_vscode_config.mdx b/api_docs/kbn_managed_vscode_config.mdx index 7fcf1d7683424..72b2f58c37a28 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index 908df05ea1618..09fdda43ed72f 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.devdocs.json b/api_docs/kbn_ml_agg_utils.devdocs.json index 66853f1a777b1..a03c944a44643 100644 --- a/api_docs/kbn_ml_agg_utils.devdocs.json +++ b/api_docs/kbn_ml_agg_utils.devdocs.json @@ -29,7 +29,7 @@ "\nWraps the supplied aggregations in a sampler aggregation.\nA supplied samplerShardSize (the shard_size parameter of the sampler aggregation)\nof less than 1 indicates no sampling, and the aggs are returned as-is." ], "signature": [ - "(aggs: any, samplerShardSize: number) => Record<string, ", + "(aggs: any, shardSize: number) => Record<string, ", "AggregationsAggregationContainer", ">" ], @@ -57,7 +57,7 @@ "id": "def-common.buildSamplerAggregation.$2", "type": "number", "tags": [], - "label": "samplerShardSize", + "label": "shardSize", "description": [], "signature": [ "number" @@ -101,7 +101,7 @@ }, "[], samplerShardSize: number, runtimeMappings?: ", "MappingRuntimeFields", - " | undefined, abortSignal?: AbortSignal | undefined, randomSamplerProbability?: number | undefined) => Promise<", + " | undefined, abortSignal?: AbortSignal | undefined, randomSamplerProbability?: number | undefined, randomSamplerSeed?: number | undefined) => Promise<", { "pluginId": "@kbn/ml-agg-utils", "scope": "common", @@ -248,6 +248,21 @@ "deprecated": false, "trackAdoption": false, "isRequired": false + }, + { + "parentPluginId": "@kbn/ml-agg-utils", + "id": "def-common.fetchAggIntervals.$9", + "type": "number", + "tags": [], + "label": "randomSamplerSeed", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "x-pack/packages/ml/agg_utils/src/fetch_agg_intervals.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false } ], "returnComment": [], @@ -281,7 +296,7 @@ }, ", samplerShardSize: number, runtimeMappings?: ", "MappingRuntimeFields", - " | undefined, abortSignal?: AbortSignal | undefined, randomSamplerProbability?: number | undefined) => Promise<(", + " | undefined, abortSignal?: AbortSignal | undefined, randomSamplerProbability?: number | undefined, randomSamplerSeed?: number | undefined) => Promise<(", { "pluginId": "@kbn/ml-agg-utils", "scope": "common", @@ -441,44 +456,28 @@ "deprecated": false, "trackAdoption": false, "isRequired": false - } - ], - "returnComment": [ - "an array of histogram data for each supplied field" - ], - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/ml-agg-utils", - "id": "def-common.getSampleProbability", - "type": "Function", - "tags": [], - "label": "getSampleProbability", - "description": [], - "signature": [ - "(totalDocCount: number) => number" - ], - "path": "x-pack/packages/ml/agg_utils/src/get_sample_probability.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + }, { "parentPluginId": "@kbn/ml-agg-utils", - "id": "def-common.getSampleProbability.$1", + "id": "def-common.fetchHistogramsForFields.$9", "type": "number", "tags": [], - "label": "totalDocCount", - "description": [], + "label": "randomSamplerSeed", + "description": [ + "optional random sampler seed" + ], "signature": [ - "number" + "number | undefined" ], - "path": "x-pack/packages/ml/agg_utils/src/get_sample_probability.ts", + "path": "x-pack/packages/ml/agg_utils/src/fetch_histograms_for_fields.ts", "deprecated": false, "trackAdoption": false, - "isRequired": true + "isRequired": false } ], - "returnComment": [], + "returnComment": [ + "an array of histogram data for each supplied field" + ], "initialIsOpen": false }, { @@ -1604,21 +1603,6 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/ml-agg-utils", - "id": "def-common.RANDOM_SAMPLER_SEED", - "type": "number", - "tags": [], - "label": "RANDOM_SAMPLER_SEED", - "description": [], - "signature": [ - "3867412" - ], - "path": "x-pack/packages/ml/agg_utils/src/constants.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false } ], "objects": [] diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index a463fd0949ef9..52caf6e355209 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-agg-utils'] --- import kbnMlAggUtilsObj from './kbn_ml_agg_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 92 | 2 | 63 | 0 | +| 91 | 2 | 61 | 0 | ## Common diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index 48bd49351683a..6253c8dc30a79 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: 2023-04-11 +date: 2023-04-12 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_is_defined.mdx b/api_docs/kbn_ml_is_defined.mdx index e5dd0452a4399..b7d09603391ab 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: 2023-04-11 +date: 2023-04-12 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 f22278a870eeb..084b2ad958063 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: 2023-04-11 +date: 2023-04-12 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_local_storage.mdx b/api_docs/kbn_ml_local_storage.mdx index 0b98a5ef63624..982d37a2b7990 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: 2023-04-11 +date: 2023-04-12 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 99ab135e863ef..487a2ff5e45b4 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: 2023-04-11 +date: 2023-04-12 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_query_utils.mdx b/api_docs/kbn_ml_query_utils.mdx index 970adfd3986c8..70a89e293f12d 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: 2023-04-11 +date: 2023-04-12 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.devdocs.json b/api_docs/kbn_ml_random_sampler_utils.devdocs.json new file mode 100644 index 0000000000000..d34965780d9b0 --- /dev/null +++ b/api_docs/kbn_ml_random_sampler_utils.devdocs.json @@ -0,0 +1,136 @@ +{ + "id": "@kbn/ml-random-sampler-utils", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/ml-random-sampler-utils", + "id": "def-common.createRandomSamplerWrapper", + "type": "Function", + "tags": [], + "label": "createRandomSamplerWrapper", + "description": [ + "\nFactory to create the random sampler wrapper utility." + ], + "signature": [ + "(options: RandomSamplerOptions) => { wrap: <T extends Record<string, ", + "AggregationsAggregationContainer", + ">>(aggs: T) => Record<string, ", + "AggregationsAggregationContainer", + "> | T; unwrap: <T extends Record<string, ", + "AggregationsAggregate", + ">>(responseAggs: T) => T | T[string]; probability: number; }" + ], + "path": "x-pack/packages/ml/random_sampler_utils/src/random_sampler_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ml-random-sampler-utils", + "id": "def-common.createRandomSamplerWrapper.$1", + "type": "CompoundType", + "tags": [], + "label": "options", + "description": [ + "RandomSamplerOptions" + ], + "signature": [ + "RandomSamplerOptions" + ], + "path": "x-pack/packages/ml/random_sampler_utils/src/random_sampler_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [ + "random sampler wrapper utility" + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ml-random-sampler-utils", + "id": "def-common.getSampleProbability", + "type": "Function", + "tags": [], + "label": "getSampleProbability", + "description": [ + "\nReturns a dynamic sample probability to be used with the `random_sampler` aggregation." + ], + "signature": [ + "(totalDocCount: number) => number" + ], + "path": "x-pack/packages/ml/random_sampler_utils/src/get_sample_probability.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ml-random-sampler-utils", + "id": "def-common.getSampleProbability.$1", + "type": "number", + "tags": [], + "label": "totalDocCount", + "description": [ + "The total document count to derive the sample probability from." + ], + "signature": [ + "number" + ], + "path": "x-pack/packages/ml/random_sampler_utils/src/get_sample_probability.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [ + "sample probability" + ], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/ml-random-sampler-utils", + "id": "def-common.RandomSamplerWrapper", + "type": "Type", + "tags": [], + "label": "RandomSamplerWrapper", + "description": [ + "\nThe return type of the `createRandomSamplerWrapper` factory." + ], + "signature": [ + "{ wrap: <T extends Record<string, ", + "AggregationsAggregationContainer", + ">>(aggs: T) => Record<string, ", + "AggregationsAggregationContainer", + "> | T; unwrap: <T extends Record<string, ", + "AggregationsAggregate", + ">>(responseAggs: T) => T | T[string]; probability: number; }" + ], + "path": "x-pack/packages/ml/random_sampler_utils/src/random_sampler_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_ml_random_sampler_utils.mdx b/api_docs/kbn_ml_random_sampler_utils.mdx new file mode 100644 index 0000000000000..4b6913e5860f0 --- /dev/null +++ b/api_docs/kbn_ml_random_sampler_utils.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: kibKbnMlRandomSamplerUtilsPluginApi +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: 2023-04-12 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-random-sampler-utils'] +--- +import kbnMlRandomSamplerUtilsObj from './kbn_ml_random_sampler_utils.devdocs.json'; + + + +Contact [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 5 | 0 | 0 | 0 | + +## Common + +### Functions +<DocDefinitionList data={kbnMlRandomSamplerUtilsObj.common.functions}/> + +### Consts, variables and types +<DocDefinitionList data={kbnMlRandomSamplerUtilsObj.common.misc}/> + diff --git a/api_docs/kbn_ml_route_utils.mdx b/api_docs/kbn_ml_route_utils.mdx index 8611a4f6ace6f..70daf4f9a5da2 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: 2023-04-11 +date: 2023-04-12 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_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index de5a9aae81e2c..c74ef0b7cc75f 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: 2023-04-11 +date: 2023-04-12 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_trained_models_utils.mdx b/api_docs/kbn_ml_trained_models_utils.mdx index 8dd155f839df5..ab64411f73321 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: 2023-04-11 +date: 2023-04-12 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_url_state.mdx b/api_docs/kbn_ml_url_state.mdx index 326808f9e9b55..ef14a63ed5483 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-url-state'] --- import kbnMlUrlStateObj from './kbn_ml_url_state.devdocs.json'; diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index c52bb7ad2a07b..5b8a9501d4d53 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: 2023-04-11 +date: 2023-04-12 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 08110ade893cd..062022ea194a7 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: 2023-04-11 +date: 2023-04-12 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 7db24525b3614..b7bbf01095841 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alert-details'] --- import kbnObservabilityAlertDetailsObj from './kbn_observability_alert_details.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index 49278772b8e3e..b21813adea2ac 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: 2023-04-11 +date: 2023-04-12 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 75f112964af76..293621505e74a 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: 2023-04-11 +date: 2023-04-12 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 09485fae739a7..3c04679e12986 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: 2023-04-11 +date: 2023-04-12 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_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index 7aa17afba83fe..299973095847a 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: 2023-04-11 +date: 2023-04-12 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_generator.mdx b/api_docs/kbn_plugin_generator.mdx index 2edd0ee811676..b5430b28f58db 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: 2023-04-11 +date: 2023-04-12 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 e109656359c00..48f5e5bd5987f 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index 6711d6423ab8d..1ce8c8cdba632 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index 18f12a01f16f6..fbdbcd409a92b 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: 2023-04-11 +date: 2023-04-12 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 1cbc6374fbd17..f9e34bbf5a303 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: 2023-04-11 +date: 2023-04-12 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 e3b11126c9c2a..ecc7f5f6009b6 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: 2023-04-11 +date: 2023-04-12 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 f345ed67c5bb0..cb8871c4bce1c 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index 016d4f3c1c96f..a4677e9366836 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index 53e2b5b17ad24..c236a08e6aea4 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_security_solution_side_nav.mdx b/api_docs/kbn_security_solution_side_nav.mdx index 7104b9f849eca..df9e060f091be 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: 2023-04-11 +date: 2023-04-12 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 f40be6cdd9da3..5243a108e8297 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: 2023-04-11 +date: 2023-04-12 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 c665c282f9d7f..ed1363898d4e9 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_ecs.mdx b/api_docs/kbn_securitysolution_ecs.mdx index cf2fefdb0a8ef..b7e272d263327 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: 2023-04-11 +date: 2023-04-12 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 96509f273d85d..4b20e499ca920 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: 2023-04-11 +date: 2023-04-12 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 f093fc23617e9..5170578753477 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: 2023-04-11 +date: 2023-04-12 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_grouping.mdx b/api_docs/kbn_securitysolution_grouping.mdx index a39108122b523..d39e1cf3095dc 100644 --- a/api_docs/kbn_securitysolution_grouping.mdx +++ b/api_docs/kbn_securitysolution_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-grouping title: "@kbn/securitysolution-grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-grouping plugin -date: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-grouping'] --- import kbnSecuritysolutionGroupingObj from './kbn_securitysolution_grouping.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index f96da1aaabc30..2141609388fa7 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: 2023-04-11 +date: 2023-04-12 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.devdocs.json b/api_docs/kbn_securitysolution_io_ts_alerting_types.devdocs.json index 542e7ce207adb..59129f93d4ed5 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.devdocs.json +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.devdocs.json @@ -303,7 +303,7 @@ "section": "def-common.SavedObjectAttributes", "text": "SavedObjectAttributes" }, - "; } & { uuid?: string | undefined; }" + "; } & { uuid?: string | undefined; alerts_filter?: { query: ({ kql: string; } & { dsl?: string | undefined; }) | null; timeframe: { timezone: string; days: (2 | 7 | 6 | 5 | 4 | 3 | 1)[]; hours: { start: string; end: string; }; } | null; } | undefined; }" ], "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, @@ -326,7 +326,7 @@ "section": "def-common.SavedObjectAttributes", "text": "SavedObjectAttributes" }, - "; } & { uuid?: string | undefined; })[]" + "; } & { uuid?: string | undefined; alerts_filter?: { query: ({ kql: string; } & { dsl?: string | undefined; }) | null; timeframe: { timezone: string; days: (2 | 7 | 6 | 5 | 4 | 3 | 1)[]; hours: { start: string; end: string; }; } | null; } | undefined; })[]" ], "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, @@ -349,7 +349,7 @@ "section": "def-common.SavedObjectAttributes", "text": "SavedObjectAttributes" }, - "; } & { uuid?: string | undefined; })[]" + "; } & { uuid?: string | undefined; alertsFilter?: { query: ({ kql: string; } & { dsl?: string | undefined; }) | null; timeframe: { timezone: string; days: (2 | 7 | 6 | 5 | 4 | 3 | 1)[]; hours: { start: string; end: string; }; } | null; } | undefined; })[]" ], "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, @@ -372,7 +372,7 @@ "section": "def-common.SavedObjectAttributes", "text": "SavedObjectAttributes" }, - "; } & { uuid?: string | undefined; }" + "; } & { uuid?: string | undefined; alertsFilter?: { query: ({ kql: string; } & { dsl?: string | undefined; }) | null; timeframe: { timezone: string; days: (2 | 7 | 6 | 5 | 4 | 3 | 1)[]; hours: { start: string; end: string; }; } | null; } | undefined; }" ], "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, @@ -1013,7 +1013,7 @@ "section": "def-common.SavedObjectAttributes", "text": "SavedObjectAttributes" }, - "; } & { uuid?: string | undefined; })[], ({ group: string; id: string; action_type_id: string; params: ", + "; } & { uuid?: string | undefined; alerts_filter?: { query: ({ kql: string; } & { dsl?: string | undefined; }) | null; timeframe: { timezone: string; days: (2 | 7 | 6 | 5 | 4 | 3 | 1)[]; hours: { start: string; end: string; }; } | null; } | undefined; })[], ({ group: string; id: string; action_type_id: string; params: ", { "pluginId": "@kbn/securitysolution-io-ts-alerting-types", "scope": "common", @@ -1021,7 +1021,7 @@ "section": "def-common.SavedObjectAttributes", "text": "SavedObjectAttributes" }, - "; } & { uuid?: string | undefined; })[] | undefined, unknown>" + "; } & { uuid?: string | undefined; alerts_filter?: { query: ({ kql: string; } & { dsl?: string | undefined; }) | null; timeframe: { timezone: string; days: (2 | 7 | 6 | 5 | 4 | 3 | 1)[]; hours: { start: string; end: string; }; } | null; } | undefined; })[] | undefined, unknown>" ], "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/default_actions_array/index.ts", "deprecated": false, @@ -1569,7 +1569,133 @@ "PartialC", "<{ uuid: ", "Type", - "<string, string, unknown>; }>]>>" + "<string, string, unknown>; alerts_filter: ", + "ExactC", + "<", + "TypeC", + "<{ query: ", + "UnionC", + "<[", + "NullC", + ", ", + "IntersectionC", + "<[", + "ExactC", + "<", + "TypeC", + "<{ kql: ", + "StringC", + "; }>>, ", + "PartialC", + "<{ dsl: ", + "StringC", + "; }>]>]>; timeframe: ", + "UnionC", + "<[", + "NullC", + ", ", + "ExactC", + "<", + "TypeC", + "<{ timezone: ", + "StringC", + "; days: ", + "ArrayC", + "<", + "UnionC", + "<[", + "LiteralC", + "<1>, ", + "LiteralC", + "<2>, ", + "LiteralC", + "<3>, ", + "LiteralC", + "<4>, ", + "LiteralC", + "<5>, ", + "LiteralC", + "<6>, ", + "LiteralC", + "<7>]>>; hours: ", + "ExactC", + "<", + "TypeC", + "<{ start: ", + "StringC", + "; end: ", + "StringC", + "; }>>; }>>]>; }>>; }>]>>" + ], + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", + "id": "def-common.RuleActionAlertsFilter", + "type": "Object", + "tags": [], + "label": "RuleActionAlertsFilter", + "description": [], + "signature": [ + "ExactC", + "<", + "TypeC", + "<{ query: ", + "UnionC", + "<[", + "NullC", + ", ", + "IntersectionC", + "<[", + "ExactC", + "<", + "TypeC", + "<{ kql: ", + "StringC", + "; }>>, ", + "PartialC", + "<{ dsl: ", + "StringC", + "; }>]>]>; timeframe: ", + "UnionC", + "<[", + "NullC", + ", ", + "ExactC", + "<", + "TypeC", + "<{ timezone: ", + "StringC", + "; days: ", + "ArrayC", + "<", + "UnionC", + "<[", + "LiteralC", + "<1>, ", + "LiteralC", + "<2>, ", + "LiteralC", + "<3>, ", + "LiteralC", + "<4>, ", + "LiteralC", + "<5>, ", + "LiteralC", + "<6>, ", + "LiteralC", + "<7>]>>; hours: ", + "ExactC", + "<", + "TypeC", + "<{ start: ", + "StringC", + "; end: ", + "StringC", + "; }>>; }>>]>; }>>" ], "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, @@ -1619,7 +1745,63 @@ "PartialC", "<{ uuid: ", "Type", - "<string, string, unknown>; }>]>>>" + "<string, string, unknown>; alerts_filter: ", + "ExactC", + "<", + "TypeC", + "<{ query: ", + "UnionC", + "<[", + "NullC", + ", ", + "IntersectionC", + "<[", + "ExactC", + "<", + "TypeC", + "<{ kql: ", + "StringC", + "; }>>, ", + "PartialC", + "<{ dsl: ", + "StringC", + "; }>]>]>; timeframe: ", + "UnionC", + "<[", + "NullC", + ", ", + "ExactC", + "<", + "TypeC", + "<{ timezone: ", + "StringC", + "; days: ", + "ArrayC", + "<", + "UnionC", + "<[", + "LiteralC", + "<1>, ", + "LiteralC", + "<2>, ", + "LiteralC", + "<3>, ", + "LiteralC", + "<4>, ", + "LiteralC", + "<5>, ", + "LiteralC", + "<6>, ", + "LiteralC", + "<7>]>>; hours: ", + "ExactC", + "<", + "TypeC", + "<{ start: ", + "StringC", + "; end: ", + "StringC", + "; }>>; }>>]>; }>>; }>]>>>" ], "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, @@ -1669,7 +1851,63 @@ "PartialC", "<{ uuid: ", "Type", - "<string, string, unknown>; }>]>>>" + "<string, string, unknown>; alertsFilter: ", + "ExactC", + "<", + "TypeC", + "<{ query: ", + "UnionC", + "<[", + "NullC", + ", ", + "IntersectionC", + "<[", + "ExactC", + "<", + "TypeC", + "<{ kql: ", + "StringC", + "; }>>, ", + "PartialC", + "<{ dsl: ", + "StringC", + "; }>]>]>; timeframe: ", + "UnionC", + "<[", + "NullC", + ", ", + "ExactC", + "<", + "TypeC", + "<{ timezone: ", + "StringC", + "; days: ", + "ArrayC", + "<", + "UnionC", + "<[", + "LiteralC", + "<1>, ", + "LiteralC", + "<2>, ", + "LiteralC", + "<3>, ", + "LiteralC", + "<4>, ", + "LiteralC", + "<5>, ", + "LiteralC", + "<6>, ", + "LiteralC", + "<7>]>>; hours: ", + "ExactC", + "<", + "TypeC", + "<{ start: ", + "StringC", + "; end: ", + "StringC", + "; }>>; }>>]>; }>>; }>]>>>" ], "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, @@ -1717,7 +1955,63 @@ "PartialC", "<{ uuid: ", "Type", - "<string, string, unknown>; }>]>>" + "<string, string, unknown>; alertsFilter: ", + "ExactC", + "<", + "TypeC", + "<{ query: ", + "UnionC", + "<[", + "NullC", + ", ", + "IntersectionC", + "<[", + "ExactC", + "<", + "TypeC", + "<{ kql: ", + "StringC", + "; }>>, ", + "PartialC", + "<{ dsl: ", + "StringC", + "; }>]>]>; timeframe: ", + "UnionC", + "<[", + "NullC", + ", ", + "ExactC", + "<", + "TypeC", + "<{ timezone: ", + "StringC", + "; days: ", + "ArrayC", + "<", + "UnionC", + "<[", + "LiteralC", + "<1>, ", + "LiteralC", + "<2>, ", + "LiteralC", + "<3>, ", + "LiteralC", + "<4>, ", + "LiteralC", + "<5>, ", + "LiteralC", + "<6>, ", + "LiteralC", + "<7>]>>; hours: ", + "ExactC", + "<", + "TypeC", + "<{ start: ", + "StringC", + "; end: ", + "StringC", + "; }>>; }>>]>; }>>; }>]>>" ], "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, diff --git a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx index 4a228e3f002e8..df799f8867ae1 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-alerting-types'] --- import kbnSecuritysolutionIoTsAlertingTypesObj from './kbn_securitysolution_io_ts_alerting_types.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-solution-platform](https://github.com/orgs/elastic/te | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 140 | 0 | 121 | 0 | +| 141 | 0 | 122 | 0 | ## Common diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index 379375a7a529e..16871fa0d23a1 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: 2023-04-11 +date: 2023-04-12 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 c3b3f57a87a7e..2c4cad29f0945 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: 2023-04-11 +date: 2023-04-12 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 6fdae1d9bcf39..16b7aedb45135 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: 2023-04-11 +date: 2023-04-12 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 d40a2f2280ee6..e74467930db83 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: 2023-04-11 +date: 2023-04-12 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 3795a672afa71..77506f4e145b0 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: 2023-04-11 +date: 2023-04-12 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 0c94bdd96638b..0e5bc206e25c3 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: 2023-04-11 +date: 2023-04-12 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 dd89fc04a41bb..02ebb67c26306 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: 2023-04-11 +date: 2023-04-12 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 335b8c5bb6cff..b2417073f2f98 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: 2023-04-11 +date: 2023-04-12 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 1a97cf10718b8..6cdd963a49448 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: 2023-04-11 +date: 2023-04-12 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 4d19d00f0a80e..f1553444ed8f4 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: 2023-04-11 +date: 2023-04-12 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 dc79d076e09a9..6a8a14808c3ac 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: 2023-04-11 +date: 2023-04-12 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 32bc36b34c464..51f48ca53cd88 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index ce42feb1d4999..c22fce494ae9a 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: 2023-04-11 +date: 2023-04-12 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 987678c3005a3..960c17cc5cce7 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: 2023-04-11 +date: 2023-04-12 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_avatar_user_profile_components.mdx b/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx index 145007a30dc85..40762e03ef793 100644 --- a/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx +++ b/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-user-profile-components title: "@kbn/shared-ux-avatar-user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-user-profile-components plugin -date: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-user-profile-components'] --- import kbnSharedUxAvatarUserProfileComponentsObj from './kbn_shared_ux_avatar_user_profile_components.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 5ce89a20dfa14..47845fd62c467 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: 2023-04-11 +date: 2023-04-12 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_exit_full_screen_mocks.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx index 26f27714b17be..328b1fb86c717 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen-mocks title: "@kbn/shared-ux-button-exit-full-screen-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen-mocks plugin -date: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen-mocks'] --- import kbnSharedUxButtonExitFullScreenMocksObj from './kbn_shared_ux_button_exit_full_screen_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index 865a4e06a47d2..ff56e7297ce9f 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: 2023-04-11 +date: 2023-04-12 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 f8390c5fa07ad..19fe0b38f81ad 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: 2023-04-11 +date: 2023-04-12 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 34b4ec1dbf64a..e7e8b06932251 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: 2023-04-11 +date: 2023-04-12 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_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index 421c5b29dfa82..e1ad64fdaa28a 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: 2023-04-11 +date: 2023-04-12 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 39ddee266c8a0..49e593b8cce03 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: 2023-04-11 +date: 2023-04-12 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 de4df5e8d33ad..5f4ad191a97c4 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: 2023-04-11 +date: 2023-04-12 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 e56514b626eda..759681ec1c419 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: 2023-04-11 +date: 2023-04-12 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 9bd16bf6b2b4a..44c9381332815 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: 2023-04-11 +date: 2023-04-12 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 308e7163d6526..b4d83bf8c48fe 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: 2023-04-11 +date: 2023-04-12 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 05f7caa0426fb..e6a4601ec8df4 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: 2023-04-11 +date: 2023-04-12 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 319eff1bc1ada..3aadd0ef130d0 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: 2023-04-11 +date: 2023-04-12 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 d017fd6b9e057..6015866461722 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: 2023-04-11 +date: 2023-04-12 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 27f6c18a0613b..f19ad9af80cf3 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: 2023-04-11 +date: 2023-04-12 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 95e266183acd8..5e447d6004d4c 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: 2023-04-11 +date: 2023-04-12 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 d610717c568a8..0cf726ec60a4e 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: 2023-04-11 +date: 2023-04-12 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 63cc2e9a175e1..99a9b099ad6f8 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: 2023-04-11 +date: 2023-04-12 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 2c5b9bd85df99..ede8a6dda71d6 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: 2023-04-11 +date: 2023-04-12 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 f2b8b4936d4d6..f0589ad58140f 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: 2023-04-11 +date: 2023-04-12 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 72f79d9edd0b8..f5008fe3a59fb 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: 2023-04-11 +date: 2023-04-12 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 100763e7276e6..80d30b775fc3c 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: 2023-04-11 +date: 2023-04-12 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 fc27c496259e1..a02c496af022f 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: 2023-04-11 +date: 2023-04-12 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 e460690d42000..ddb86671f94d8 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: 2023-04-11 +date: 2023-04-12 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 882ae9c9c9050..ded9ec15470a3 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: 2023-04-11 +date: 2023-04-12 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 1fb44f1ea1f74..99268ff7b52bb 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: 2023-04-11 +date: 2023-04-12 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 635218abd589b..72cb1c875d2f5 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: 2023-04-11 +date: 2023-04-12 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 d9f0a178575e3..11c288ebc8dcb 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: 2023-04-11 +date: 2023-04-12 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 ac9d4be701451..6a1542396552a 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: 2023-04-11 +date: 2023-04-12 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 0b827dedb5e88..567f1ce223380 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: 2023-04-11 +date: 2023-04-12 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 fbb92bea91fd7..6ea131269f9c5 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: 2023-04-11 +date: 2023-04-12 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 87b75b9d01f24..7dd49a7d8ad7f 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: 2023-04-11 +date: 2023-04-12 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 6924f507f90f7..a509379387db5 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: 2023-04-11 +date: 2023-04-12 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 9cd3e7b57ca73..fa5ea89da3d17 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: 2023-04-11 +date: 2023-04-12 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 4eea5ee75e249..120bbc686f1e5 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: 2023-04-11 +date: 2023-04-12 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_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index 6f03641b6fd90..e85c73ae856f6 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: 2023-04-11 +date: 2023-04-12 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 cee883ed3a1c0..7d8d15238bfeb 100644 --- a/api_docs/kbn_slo_schema.devdocs.json +++ b/api_docs/kbn_slo_schema.devdocs.json @@ -390,7 +390,7 @@ "label": "CreateSLOInput", "description": [], "signature": [ - "{ name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; } & { timestampField?: string | undefined; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; } & { settings?: { syncDelay?: string | undefined; frequency?: string | undefined; } | undefined; tags?: string[] | undefined; }" + "{ name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; timestampField: string; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; } & { settings?: { syncDelay?: string | undefined; frequency?: string | undefined; } | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -405,7 +405,7 @@ "label": "CreateSLOParams", "description": [], "signature": [ - "{ name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; } & { timestampField?: string | undefined; }; }; timeWindow: { duration: ", + "{ name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; timestampField: string; }; }; timeWindow: { duration: ", { "pluginId": "@kbn/slo-schema", "scope": "common", @@ -505,7 +505,7 @@ "label": "FindSLOParams", "description": [], "signature": [ - "{ name?: string | undefined; indicatorTypes?: string[] | undefined; page?: string | undefined; perPage?: string | undefined; sortBy?: \"name\" | \"indicatorType\" | undefined; sortDirection?: \"asc\" | \"desc\" | undefined; }" + "{ name?: string | undefined; indicatorTypes?: string[] | undefined; page?: string | undefined; perPage?: string | undefined; sortBy?: \"creationTime\" | \"indicatorType\" | undefined; sortDirection?: \"asc\" | \"desc\" | undefined; }" ], "path": "packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -520,7 +520,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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; } & { timestampField?: string | undefined; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; })[]; }" + "{ 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; timestampField: string; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; })[]; }" ], "path": "packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -535,7 +535,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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; } & { timestampField?: string | undefined; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; }" + "{ 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; timestampField: string; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; }" ], "path": "packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -580,7 +580,7 @@ "label": "SLOResponse", "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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; } & { timestampField?: string | undefined; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; }" + "{ 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; timestampField: string; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; }" ], "path": "packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -595,7 +595,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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; } & { timestampField?: string | undefined; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; }" + "{ 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; timestampField: string; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; }" ], "path": "packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -610,7 +610,7 @@ "label": "UpdateSLOInput", "description": [], "signature": [ - "{ name?: string | undefined; description?: string | undefined; indicator?: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; } & { timestampField?: string | undefined; }; } | undefined; timeWindow?: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; } | undefined; budgetingMethod?: \"occurrences\" | \"timeslices\" | undefined; objective?: ({ target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }) | undefined; settings?: { syncDelay?: string | undefined; frequency?: string | undefined; } | undefined; tags?: string[] | undefined; }" + "{ name?: string | undefined; description?: string | undefined; indicator?: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; timestampField: string; }; } | undefined; timeWindow?: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; } | undefined; budgetingMethod?: \"occurrences\" | \"timeslices\" | undefined; objective?: ({ target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }) | undefined; settings?: { syncDelay?: string | undefined; frequency?: string | undefined; } | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -625,7 +625,7 @@ "label": "UpdateSLOParams", "description": [], "signature": [ - "{ name?: string | undefined; description?: string | undefined; indicator?: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; } & { timestampField?: string | undefined; }; } | undefined; timeWindow?: { duration: ", + "{ name?: string | undefined; description?: string | undefined; indicator?: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; timestampField: string; }; } | undefined; timeWindow?: { duration: ", { "pluginId": "@kbn/slo-schema", "scope": "common", @@ -680,7 +680,7 @@ "label": "UpdateSLOResponse", "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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; } & { timestampField?: string | undefined; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; }" + "{ 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; timestampField: string; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; }" ], "path": "packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -1023,8 +1023,6 @@ "<{ type: ", "LiteralC", "<\"sli.kql.custom\">; params: ", - "IntersectionC", - "<[", "TypeC", "<{ index: ", "StringC", @@ -1034,11 +1032,9 @@ "StringC", "; total: ", "StringC", - "; }>, ", - "PartialC", - "<{ timestampField: ", + "; timestampField: ", "StringC", - "; }>]>; }>]>; timeWindow: ", + "; }>; }>]>; timeWindow: ", "UnionC", "<[", "TypeC", @@ -1330,7 +1326,7 @@ "UnionC", "<[", "LiteralC", - "<\"name\">, ", + "<\"creationTime\">, ", "LiteralC", "<\"indicatorType\">]>; sortDirection: ", "UnionC", @@ -1469,8 +1465,6 @@ "<{ type: ", "LiteralC", "<\"sli.kql.custom\">; params: ", - "IntersectionC", - "<[", "TypeC", "<{ index: ", "StringC", @@ -1480,11 +1474,9 @@ "StringC", "; total: ", "StringC", - "; }>, ", - "PartialC", - "<{ timestampField: ", + "; timestampField: ", "StringC", - "; }>]>; }>]>; timeWindow: ", + "; }>; }>]>; timeWindow: ", "UnionC", "<[", "TypeC", @@ -1763,8 +1755,6 @@ "<{ type: ", "LiteralC", "<\"sli.kql.custom\">; params: ", - "IntersectionC", - "<[", "TypeC", "<{ index: ", "StringC", @@ -1774,11 +1764,9 @@ "StringC", "; total: ", "StringC", - "; }>, ", - "PartialC", - "<{ timestampField: ", + "; timestampField: ", "StringC", - "; }>]>; }>]>; timeWindow: ", + "; }>; }>]>; timeWindow: ", "UnionC", "<[", "TypeC", @@ -2077,8 +2065,6 @@ "<{ type: ", "LiteralC", "<\"sli.kql.custom\">; params: ", - "IntersectionC", - "<[", "TypeC", "<{ index: ", "StringC", @@ -2088,11 +2074,9 @@ "StringC", "; total: ", "StringC", - "; }>, ", - "PartialC", - "<{ timestampField: ", + "; timestampField: ", "StringC", - "; }>]>; }>]>" + "; }>; }>]>" ], "path": "packages/kbn-slo-schema/src/schema/indicators.ts", "deprecated": false, @@ -2149,8 +2133,6 @@ "<{ type: ", "LiteralC", "<\"sli.kql.custom\">; params: ", - "IntersectionC", - "<[", "TypeC", "<{ index: ", "StringC", @@ -2160,11 +2142,9 @@ "StringC", "; total: ", "StringC", - "; }>, ", - "PartialC", - "<{ timestampField: ", + "; timestampField: ", "StringC", - "; }>]>; }>" + "; }>; }>" ], "path": "packages/kbn-slo-schema/src/schema/indicators.ts", "deprecated": false, @@ -2484,8 +2464,6 @@ "<{ type: ", "LiteralC", "<\"sli.kql.custom\">; params: ", - "IntersectionC", - "<[", "TypeC", "<{ index: ", "StringC", @@ -2495,11 +2473,9 @@ "StringC", "; total: ", "StringC", - "; }>, ", - "PartialC", - "<{ timestampField: ", + "; timestampField: ", "StringC", - "; }>]>; }>]>; timeWindow: ", + "; }>; }>]>; timeWindow: ", "UnionC", "<[", "TypeC", @@ -2710,8 +2686,6 @@ "<{ type: ", "LiteralC", "<\"sli.kql.custom\">; params: ", - "IntersectionC", - "<[", "TypeC", "<{ index: ", "StringC", @@ -2721,11 +2695,9 @@ "StringC", "; total: ", "StringC", - "; }>, ", - "PartialC", - "<{ timestampField: ", + "; timestampField: ", "StringC", - "; }>]>; }>]>; timeWindow: ", + "; }>; }>]>; timeWindow: ", "UnionC", "<[", "TypeC", @@ -2938,8 +2910,6 @@ "<{ type: ", "LiteralC", "<\"sli.kql.custom\">; params: ", - "IntersectionC", - "<[", "TypeC", "<{ index: ", "StringC", @@ -2949,11 +2919,9 @@ "StringC", "; total: ", "StringC", - "; }>, ", - "PartialC", - "<{ timestampField: ", + "; timestampField: ", "StringC", - "; }>]>; }>]>; timeWindow: ", + "; }>; }>]>; timeWindow: ", "UnionC", "<[", "TypeC", @@ -3192,8 +3160,6 @@ "<{ type: ", "LiteralC", "<\"sli.kql.custom\">; params: ", - "IntersectionC", - "<[", "TypeC", "<{ index: ", "StringC", @@ -3203,11 +3169,9 @@ "StringC", "; total: ", "StringC", - "; }>, ", - "PartialC", - "<{ timestampField: ", + "; timestampField: ", "StringC", - "; }>]>; }>]>; timeWindow: ", + "; }>; }>]>; timeWindow: ", "UnionC", "<[", "TypeC", @@ -3590,8 +3554,6 @@ "<{ type: ", "LiteralC", "<\"sli.kql.custom\">; params: ", - "IntersectionC", - "<[", "TypeC", "<{ index: ", "StringC", @@ -3601,11 +3563,9 @@ "StringC", "; total: ", "StringC", - "; }>, ", - "PartialC", - "<{ timestampField: ", + "; timestampField: ", "StringC", - "; }>]>; }>]>; timeWindow: ", + "; }>; }>]>; timeWindow: ", "UnionC", "<[", "TypeC", @@ -3808,8 +3768,6 @@ "<{ type: ", "LiteralC", "<\"sli.kql.custom\">; params: ", - "IntersectionC", - "<[", "TypeC", "<{ index: ", "StringC", @@ -3819,11 +3777,9 @@ "StringC", "; total: ", "StringC", - "; }>, ", - "PartialC", - "<{ timestampField: ", + "; timestampField: ", "StringC", - "; }>]>; }>]>; timeWindow: ", + "; }>; }>]>; timeWindow: ", "UnionC", "<[", "TypeC", diff --git a/api_docs/kbn_slo_schema.mdx b/api_docs/kbn_slo_schema.mdx index c84726b6e1805..4e2f486dbf351 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: 2023-04-11 +date: 2023-04-12 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 5f11b298cc3cb..2a8ba8b7ad2cb 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index 3268aea957cd2..269f179a899cf 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: 2023-04-11 +date: 2023-04-12 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 e5719e5ae89c8..83f00448b6450 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: 2023-04-11 +date: 2023-04-12 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 70a6661b7ee51..0551babd4acb3 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: 2023-04-11 +date: 2023-04-12 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 b3a324f9bbe16..ff88c09287156 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: 2023-04-11 +date: 2023-04-12 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 5ee2e679aca10..e78ff01b8c66d 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index 0744609373584..80448e18d6723 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: 2023-04-11 +date: 2023-04-12 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 6c52516bc9a63..e71c3c6696821 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-subj-selector'] --- import kbnTestSubjSelectorObj from './kbn_test_subj_selector.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index 4b209964739b9..cb31b80ac430e 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_ts_projects.mdx b/api_docs/kbn_ts_projects.mdx index c8c18b640df14..accae84d157d1 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: 2023-04-11 +date: 2023-04-12 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 a2c76ae7606f6..c41d37b44d167 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: 2023-04-11 +date: 2023-04-12 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 9c561bc020b0c..edcfc2f3461d2 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: 2023-04-11 +date: 2023-04-12 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 0408e196a34bc..7b752ccc117f2 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: 2023-04-11 +date: 2023-04-12 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 abc44e713c5f8..44e02a2d8a171 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index c81049904a03e..78ba4c006edd4 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: 2023-04-11 +date: 2023-04-12 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 9f73094693345..bc97f6fd7865f 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: 2023-04-11 +date: 2023-04-12 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 c5831bc86b6b8..b948bbdd3d148 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: 2023-04-11 +date: 2023-04-12 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 0b1a8f2dc46d5..979db35c9a6d1 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index 4e8d00e1b6309..c3f530a930919 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index 7abbbc111bafa..fb1ff7b9bd658 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: 2023-04-11 +date: 2023-04-12 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 ca1d951253878..f93da385d9c2a 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: 2023-04-11 +date: 2023-04-12 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 ebbfe8a524e62..0bd48654f7fde 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: 2023-04-11 +date: 2023-04-12 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 56d0958d0377c..d107645f7ca93 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: 2023-04-11 +date: 2023-04-12 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 914562196b607..67d56b637ab19 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: 2023-04-11 +date: 2023-04-12 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 0cc10206ff899..139bd5f3d569b 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: 2023-04-11 +date: 2023-04-12 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 99f9c73be1c3b..dc2bb9d1b17e1 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: 2023-04-11 +date: 2023-04-12 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 39cc41433b000..ade2b4f18b7b7 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 74c8da5ae8819..82fd58d1e580f 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index 89f040aa4b7c4..7096ff99d2b77 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: 2023-04-11 +date: 2023-04-12 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 ca4be93b79eb5..60b7c65cb2ea6 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: 2023-04-11 +date: 2023-04-12 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 f844f4fdacfe0..2c3bec5075673 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index dca5505686762..5d8d71db6e946 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index 2f41d2888a1de..381f6da728aad 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: 2023-04-11 +date: 2023-04-12 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 51097df5ce5b3..5073a5d150324 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: 2023-04-11 +date: 2023-04-12 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 408388f712a5a..c8c0082be8627 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: 2023-04-11 +date: 2023-04-12 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 9be1747080456..61e2a53fde2c6 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/notifications.mdx b/api_docs/notifications.mdx index f670f25d6e935..53ec4c5fb4693 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: 2023-04-11 +date: 2023-04-12 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 e5d2e26a3f68a..09a129e9ca3dc 100644 --- a/api_docs/observability.devdocs.json +++ b/api_docs/observability.devdocs.json @@ -10280,7 +10280,7 @@ "section": "def-common.SavedObject", "text": "SavedObject" }, - "<{ 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; } & { timestampField?: string | undefined; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; }>; sloTransformStats: ", + "<{ 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; timestampField: string; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; }>; sloTransformStats: ", "TransformGetTransformStatsResponse", "; dataSample: string | ", "SearchResponse", @@ -10439,8 +10439,6 @@ "<{ type: ", "LiteralC", "<\"sli.kql.custom\">; params: ", - "IntersectionC", - "<[", "TypeC", "<{ index: ", "StringC", @@ -10450,11 +10448,9 @@ "StringC", "; total: ", "StringC", - "; }>, ", - "PartialC", - "<{ timestampField: ", + "; timestampField: ", "StringC", - "; }>]>; }>]>; timeWindow: ", + "; }>; }>]>; timeWindow: ", "UnionC", "<[", "TypeC", @@ -10546,7 +10542,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - ", { 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; } & { timestampField?: string | undefined; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; }, ", + ", { 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; timestampField: string; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; }, ", { "pluginId": "observability", "scope": "server", @@ -10576,7 +10572,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - ", { 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; } & { timestampField?: string | undefined; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; }, ", + ", { 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; timestampField: string; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; }, ", { "pluginId": "observability", "scope": "server", @@ -10608,7 +10604,7 @@ "UnionC", "<[", "LiteralC", - "<\"name\">, ", + "<\"creationTime\">, ", "LiteralC", "<\"indicatorType\">]>; sortDirection: ", "UnionC", @@ -10624,7 +10620,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - ", { 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; } & { timestampField?: string | undefined; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; })[]; }, ", + ", { 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; timestampField: string; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; })[]; }, ", { "pluginId": "observability", "scope": "server", @@ -10869,8 +10865,6 @@ "<{ type: ", "LiteralC", "<\"sli.kql.custom\">; params: ", - "IntersectionC", - "<[", "TypeC", "<{ index: ", "StringC", @@ -10880,11 +10874,9 @@ "StringC", "; total: ", "StringC", - "; }>, ", - "PartialC", - "<{ timestampField: ", + "; timestampField: ", "StringC", - "; }>]>; }>]>; timeWindow: ", + "; }>; }>]>; timeWindow: ", "UnionC", "<[", "TypeC", @@ -11090,7 +11082,7 @@ "section": "def-common.SavedObject", "text": "SavedObject" }, - "<{ 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; } & { timestampField?: string | undefined; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; }>; sloTransformStats: ", + "<{ 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; timestampField: string; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; }>; sloTransformStats: ", "TransformGetTransformStatsResponse", "; dataSample: string | ", "SearchResponse", @@ -11249,8 +11241,6 @@ "<{ type: ", "LiteralC", "<\"sli.kql.custom\">; params: ", - "IntersectionC", - "<[", "TypeC", "<{ index: ", "StringC", @@ -11260,11 +11250,9 @@ "StringC", "; total: ", "StringC", - "; }>, ", - "PartialC", - "<{ timestampField: ", + "; timestampField: ", "StringC", - "; }>]>; }>]>; timeWindow: ", + "; }>; }>]>; timeWindow: ", "UnionC", "<[", "TypeC", @@ -11356,7 +11344,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - ", { 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; } & { timestampField?: string | undefined; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; }, ", + ", { 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; timestampField: string; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; }, ", { "pluginId": "observability", "scope": "server", @@ -11386,7 +11374,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - ", { 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; } & { timestampField?: string | undefined; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; }, ", + ", { 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; timestampField: string; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; }, ", { "pluginId": "observability", "scope": "server", @@ -11418,7 +11406,7 @@ "UnionC", "<[", "LiteralC", - "<\"name\">, ", + "<\"creationTime\">, ", "LiteralC", "<\"indicatorType\">]>; sortDirection: ", "UnionC", @@ -11434,7 +11422,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - ", { 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; } & { timestampField?: string | undefined; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; })[]; }, ", + ", { 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 | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { goodStatusCodes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; filter: string; good: string; total: string; timestampField: string; }; }; timeWindow: { duration: string; isRolling: boolean; } | { duration: string; calendar: { startTime: string; }; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; })[]; }, ", { "pluginId": "observability", "scope": "server", @@ -11679,8 +11667,6 @@ "<{ type: ", "LiteralC", "<\"sli.kql.custom\">; params: ", - "IntersectionC", - "<[", "TypeC", "<{ index: ", "StringC", @@ -11690,11 +11676,9 @@ "StringC", "; total: ", "StringC", - "; }>, ", - "PartialC", - "<{ timestampField: ", + "; timestampField: ", "StringC", - "; }>]>; }>]>; timeWindow: ", + "; }>; }>]>; timeWindow: ", "UnionC", "<[", "TypeC", diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 816fd43e50162..c19c19a20b521 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/observability_shared.devdocs.json b/api_docs/observability_shared.devdocs.json new file mode 100644 index 0000000000000..cc911b709261d --- /dev/null +++ b/api_docs/observability_shared.devdocs.json @@ -0,0 +1,565 @@ +{ + "id": "observabilityShared", + "client": { + "classes": [ + { + "parentPluginId": "observabilityShared", + "id": "def-public.ObservabilitySharedPlugin", + "type": "Class", + "tags": [], + "label": "ObservabilitySharedPlugin", + "description": [], + "signature": [ + { + "pluginId": "observabilityShared", + "scope": "public", + "docId": "kibObservabilitySharedPluginApi", + "section": "def-public.ObservabilitySharedPlugin", + "text": "ObservabilitySharedPlugin" + }, + " implements ", + { + "pluginId": "@kbn/core-plugins-browser", + "scope": "common", + "docId": "kibKbnCorePluginsBrowserPluginApi", + "section": "def-common.Plugin", + "text": "Plugin" + }, + "<void, void, object, object>" + ], + "path": "x-pack/plugins/observability_shared/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "observabilityShared", + "id": "def-public.ObservabilitySharedPlugin.setup", + "type": "Function", + "tags": [], + "label": "setup", + "description": [], + "signature": [ + "() => { navigation: { registerSections: (sections$: ", + "Observable", + "<", + "NavigationSection", + "[]>) => void; }; }" + ], + "path": "x-pack/plugins/observability_shared/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.ObservabilitySharedPlugin.start", + "type": "Function", + "tags": [], + "label": "start", + "description": [], + "signature": [ + "(core: ", + { + "pluginId": "@kbn/core-lifecycle-browser", + "scope": "common", + "docId": "kibKbnCoreLifecycleBrowserPluginApi", + "section": "def-common.CoreStart", + "text": "CoreStart" + }, + ", plugins: ", + "ObservabilitySharedStart", + ") => { navigation: { PageTemplate: (pageTemplateProps: ", + "WrappedPageTemplateProps", + ") => JSX.Element; }; updateGlobalNavigation: ({ capabilities, deepLinks, updater$, }: { capabilities: Readonly<{ [x: string]: Readonly<{ [x: string]: boolean | Readonly<{ [x: string]: boolean; }>; }>; navLinks: Readonly<{ [x: string]: boolean; }>; management: Readonly<{ [x: string]: Readonly<{ [x: string]: boolean; }>; }>; catalogue: Readonly<{ [x: string]: boolean; }>; }>; deepLinks: ", + { + "pluginId": "@kbn/core-application-browser", + "scope": "common", + "docId": "kibKbnCoreApplicationBrowserPluginApi", + "section": "def-common.AppDeepLink", + "text": "AppDeepLink" + }, + "[]; updater$: ", + "Subject", + "<", + { + "pluginId": "@kbn/core-application-browser", + "scope": "common", + "docId": "kibKbnCoreApplicationBrowserPluginApi", + "section": "def-common.AppUpdater", + "text": "AppUpdater" + }, + ">; }) => void; }" + ], + "path": "x-pack/plugins/observability_shared/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "observabilityShared", + "id": "def-public.ObservabilitySharedPlugin.start.$1", + "type": "Object", + "tags": [], + "label": "core", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-lifecycle-browser", + "scope": "common", + "docId": "kibKbnCoreLifecycleBrowserPluginApi", + "section": "def-common.CoreStart", + "text": "CoreStart" + } + ], + "path": "x-pack/plugins/observability_shared/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.ObservabilitySharedPlugin.start.$2", + "type": "Object", + "tags": [], + "label": "plugins", + "description": [], + "signature": [ + "ObservabilitySharedStart" + ], + "path": "x-pack/plugins/observability_shared/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.ObservabilitySharedPlugin.stop", + "type": "Function", + "tags": [], + "label": "stop", + "description": [], + "signature": [ + "() => void" + ], + "path": "x-pack/plugins/observability_shared/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "functions": [], + "interfaces": [ + { + "parentPluginId": "observabilityShared", + "id": "def-public.NavigationEntry", + "type": "Interface", + "tags": [], + "label": "NavigationEntry", + "description": [], + "path": "x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "observabilityShared", + "id": "def-public.NavigationEntry.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.NavigationEntry.app", + "type": "string", + "tags": [], + "label": "app", + "description": [], + "path": "x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.NavigationEntry.path", + "type": "string", + "tags": [], + "label": "path", + "description": [], + "path": "x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.NavigationEntry.matchFullPath", + "type": "CompoundType", + "tags": [], + "label": "matchFullPath", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.NavigationEntry.ignoreTrailingSlash", + "type": "CompoundType", + "tags": [], + "label": "ignoreTrailingSlash", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.NavigationEntry.onClick", + "type": "Function", + "tags": [], + "label": "onClick", + "description": [], + "signature": [ + "((event: React.MouseEvent<HTMLElement | HTMLButtonElement, MouseEvent>) => void) | undefined" + ], + "path": "x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "observabilityShared", + "id": "def-public.NavigationEntry.onClick.$1", + "type": "Object", + "tags": [], + "label": "event", + "description": [], + "signature": [ + "React.MouseEvent<HTMLElement | HTMLButtonElement, MouseEvent>" + ], + "path": "x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.NavigationEntry.isNewFeature", + "type": "CompoundType", + "tags": [], + "label": "isNewFeature", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.NavigationEntry.isTechnicalPreview", + "type": "CompoundType", + "tags": [], + "label": "isTechnicalPreview", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.NavigationEntry.isBetaFeature", + "type": "CompoundType", + "tags": [], + "label": "isBetaFeature", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.NavigationEntry.matchPath", + "type": "Function", + "tags": [], + "label": "matchPath", + "description": [], + "signature": [ + "((path: string) => boolean) | undefined" + ], + "path": "x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "observabilityShared", + "id": "def-public.NavigationEntry.matchPath.$1", + "type": "string", + "tags": [], + "label": "path", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "observabilityShared", + "id": "def-public.casesFeatureId", + "type": "string", + "tags": [], + "label": "casesFeatureId", + "description": [], + "signature": [ + "\"observabilityCases\"" + ], + "path": "x-pack/plugins/observability_shared/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.LazyObservabilityPageTemplateProps", + "type": "Type", + "tags": [], + "label": "LazyObservabilityPageTemplateProps", + "description": [], + "signature": [ + "Pick<", + "KibanaPageTemplateProps", + ", \"children\" | \"data-test-subj\" | \"paddingSize\" | \"pageHeader\" | \"restrictWidth\" | \"isEmptyState\" | \"noDataConfig\"> & { showSolutionNav?: boolean | undefined; isPageDataLoaded?: boolean | undefined; pageSectionProps?: ", + "EuiPageSectionProps", + " | undefined; bottomBar?: React.ReactNode; bottomBarProps?: ", + "_EuiPageBottomBarProps", + " | undefined; }" + ], + "path": "x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.observabilityFeatureId", + "type": "string", + "tags": [], + "label": "observabilityFeatureId", + "description": [], + "signature": [ + "\"observability\"" + ], + "path": "x-pack/plugins/observability_shared/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.ObservabilityPageTemplateProps", + "type": "Type", + "tags": [], + "label": "ObservabilityPageTemplateProps", + "description": [], + "signature": [ + "ObservabilityPageTemplateDependencies", + " & Pick<", + "KibanaPageTemplateProps", + ", \"children\" | \"data-test-subj\" | \"paddingSize\" | \"pageHeader\" | \"restrictWidth\" | \"isEmptyState\" | \"noDataConfig\"> & { showSolutionNav?: boolean | undefined; isPageDataLoaded?: boolean | undefined; pageSectionProps?: ", + "EuiPageSectionProps", + " | undefined; bottomBar?: React.ReactNode; bottomBarProps?: ", + "_EuiPageBottomBarProps", + " | undefined; }" + ], + "path": "x-pack/plugins/observability_shared/public/components/page_template/page_template.tsx", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.ObservabilitySharedPluginSetup", + "type": "Type", + "tags": [], + "label": "ObservabilitySharedPluginSetup", + "description": [], + "signature": [ + "{ navigation: { registerSections: (sections$: ", + "Observable", + "<", + "NavigationSection", + "[]>) => void; }; }" + ], + "path": "x-pack/plugins/observability_shared/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.ObservabilitySharedPluginStart", + "type": "Type", + "tags": [], + "label": "ObservabilitySharedPluginStart", + "description": [], + "signature": [ + "{ navigation: { PageTemplate: (pageTemplateProps: ", + "WrappedPageTemplateProps", + ") => JSX.Element; }; updateGlobalNavigation: ({ capabilities, deepLinks, updater$, }: { capabilities: Readonly<{ [x: string]: Readonly<{ [x: string]: boolean | Readonly<{ [x: string]: boolean; }>; }>; navLinks: Readonly<{ [x: string]: boolean; }>; management: Readonly<{ [x: string]: Readonly<{ [x: string]: boolean; }>; }>; catalogue: Readonly<{ [x: string]: boolean; }>; }>; deepLinks: ", + { + "pluginId": "@kbn/core-application-browser", + "scope": "common", + "docId": "kibKbnCoreApplicationBrowserPluginApi", + "section": "def-common.AppDeepLink", + "text": "AppDeepLink" + }, + "[]; updater$: ", + "Subject", + "<", + { + "pluginId": "@kbn/core-application-browser", + "scope": "common", + "docId": "kibKbnCoreApplicationBrowserPluginApi", + "section": "def-common.AppUpdater", + "text": "AppUpdater" + }, + ">; }) => void; }" + ], + "path": "x-pack/plugins/observability_shared/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.sloFeatureId", + "type": "string", + "tags": [], + "label": "sloFeatureId", + "description": [], + "signature": [ + "\"slo\"" + ], + "path": "x-pack/plugins/observability_shared/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [ + { + "parentPluginId": "observabilityShared", + "id": "def-common.casesFeatureId", + "type": "string", + "tags": [], + "label": "casesFeatureId", + "description": [], + "signature": [ + "\"observabilityCases\"" + ], + "path": "x-pack/plugins/observability_shared/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-common.observabilityAppId", + "type": "string", + "tags": [], + "label": "observabilityAppId", + "description": [], + "signature": [ + "\"observability-overview\"" + ], + "path": "x-pack/plugins/observability_shared/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-common.observabilityFeatureId", + "type": "string", + "tags": [], + "label": "observabilityFeatureId", + "description": [], + "signature": [ + "\"observability\"" + ], + "path": "x-pack/plugins/observability_shared/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-common.sloFeatureId", + "type": "string", + "tags": [], + "label": "sloFeatureId", + "description": [], + "signature": [ + "\"slo\"" + ], + "path": "x-pack/plugins/observability_shared/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/observability_shared.mdx b/api_docs/observability_shared.mdx new file mode 100644 index 0000000000000..71107e14c8802 --- /dev/null +++ b/api_docs/observability_shared.mdx @@ -0,0 +1,41 @@ +--- +#### +#### 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: kibObservabilitySharedPluginApi +slug: /kibana-dev-docs/api/observabilityShared +title: "observabilityShared" +image: https://source.unsplash.com/400x175/?github +description: API docs for the observabilityShared plugin +date: 2023-04-12 +tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityShared'] +--- +import observabilitySharedObj from './observability_shared.devdocs.json'; + + + +Contact [@elastic/actionable-observability](https://github.com/orgs/elastic/teams/actionable-observability) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 30 | 0 | 30 | 4 | + +## Client + +### Classes +<DocDefinitionList data={observabilitySharedObj.client.classes}/> + +### Interfaces +<DocDefinitionList data={observabilitySharedObj.client.interfaces}/> + +### Consts, variables and types +<DocDefinitionList data={observabilitySharedObj.client.misc}/> + +## Common + +### Consts, variables and types +<DocDefinitionList data={observabilitySharedObj.common.misc}/> + diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index a2444b49071aa..5ccc6f51b8671 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index cb709542e1f80..d9dd757be8807 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -15,13 +15,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Count | Plugins or Packages with a <br /> public API | Number of teams | |--------------|----------|------------------------| -| 587 | 483 | 38 | +| 589 | 485 | 38 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 68664 | 525 | 59318 | 1323 | +| 68705 | 525 | 59351 | 1328 | ## Plugin Directory @@ -30,8 +30,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | <DocLink id="kibActionsPluginApi" text="actions"/> | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 259 | 8 | 254 | 26 | | <DocLink id="kibAdvancedSettingsPluginApi" text="advancedSettings"/> | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 36 | 1 | 32 | 2 | | <DocLink id="kibAiopsPluginApi" text="aiops"/> | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | AIOps plugin maintained by ML team. | 12 | 0 | 1 | 2 | -| <DocLink id="kibAlertingPluginApi" text="alerting"/> | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 564 | 1 | 543 | 41 | -| <DocLink id="kibApmPluginApi" text="apm"/> | [@elastic/apm-ui](https://github.com/orgs/elastic/teams/apm-ui) | The user interface for Elastic APM | 42 | 0 | 42 | 108 | +| <DocLink id="kibAlertingPluginApi" text="alerting"/> | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 567 | 1 | 546 | 41 | +| <DocLink id="kibApmPluginApi" text="apm"/> | [@elastic/apm-ui](https://github.com/orgs/elastic/teams/apm-ui) | The user interface for Elastic APM | 43 | 0 | 43 | 109 | | <DocLink id="kibAssetManagerPluginApi" text="assetManager"/> | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | Asset manager plugin for entity assets (inventory, topology, etc) | 3 | 0 | 3 | 0 | | <DocLink id="kibBannersPluginApi" text="banners"/> | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 9 | 0 | 9 | 0 | | <DocLink id="kibBfetchPluginApi" text="bfetch"/> | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Considering using bfetch capabilities when fetching large amounts of data. This services supports batching HTTP requests and streaming responses back. | 91 | 1 | 75 | 2 | @@ -130,6 +130,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | <DocLink id="kibNewsfeedPluginApi" text="newsfeed"/> | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 17 | 0 | 17 | 0 | | <DocLink id="kibNotificationsPluginApi" text="notifications"/> | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 1 | | <DocLink id="kibObservabilityPluginApi" text="observability"/> | [@elastic/actionable-observability](https://github.com/orgs/elastic/teams/actionable-observability) | - | 652 | 44 | 646 | 34 | +| <DocLink id="kibObservabilitySharedPluginApi" text="observabilityShared"/> | [@elastic/actionable-observability](https://github.com/orgs/elastic/teams/actionable-observability) | - | 30 | 0 | 30 | 4 | | <DocLink id="kibOsqueryPluginApi" text="osquery"/> | [@elastic/security-defend-workflows](https://github.com/orgs/elastic/teams/security-defend-workflows) | - | 24 | 0 | 24 | 6 | | painlessLab | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | | <DocLink id="kibPresentationUtilPluginApi" text="presentationUtil"/> | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Presentation Utility Plugin is a set of common, shared components and toolkits for solutions within the Presentation space, (e.g. Dashboards, Canvas). | 207 | 8 | 151 | 12 | @@ -171,7 +172,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | <DocLink id="kibUiActionsEnhancedPluginApi" text="uiActionsEnhanced"/> | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Extends UI Actions plugin with more functionality | 206 | 0 | 140 | 9 | | <DocLink id="kibUnifiedFieldListPluginApi" text="unifiedFieldList"/> | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the field list which can be integrated into apps | 276 | 0 | 250 | 7 | | <DocLink id="kibUnifiedHistogramPluginApi" text="unifiedHistogram"/> | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | The `unifiedHistogram` plugin provides UI components to create a layout including a resizable histogram and a main display. | 52 | 0 | 23 | 2 | -| <DocLink id="kibUnifiedSearchPluginApi" text="unifiedSearch"/> | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains all the key functionality of Kibana's unified search experience.Contains all the key functionality of Kibana's unified search experience. | 135 | 2 | 100 | 20 | +| <DocLink id="kibUnifiedSearchPluginApi" text="unifiedSearch"/> | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains all the key functionality of Kibana's unified search experience.Contains all the key functionality of Kibana's unified search experience. | 137 | 2 | 100 | 20 | | upgradeAssistant | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | | urlDrilldown | [@elastic/kibana-app-services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds drilldown implementations to Kibana | 0 | 0 | 0 | 0 | | <DocLink id="kibUrlForwardingPluginApi" text="urlForwarding"/> | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 12 | 0 | 12 | 0 | @@ -432,13 +433,14 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | <DocLink id="kibKbnLoggingMocksPluginApi" text="@kbn/logging-mocks"/> | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 8 | 0 | 8 | 0 | | <DocLink id="kibKbnManagedVscodeConfigPluginApi" text="@kbn/managed-vscode-config"/> | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 6 | 0 | 1 | 1 | | <DocLink id="kibKbnMapboxGlPluginApi" text="@kbn/mapbox-gl"/> | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | - | 534 | 1 | 1 | 0 | -| <DocLink id="kibKbnMlAggUtilsPluginApi" text="@kbn/ml-agg-utils"/> | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 92 | 2 | 63 | 0 | +| <DocLink id="kibKbnMlAggUtilsPluginApi" text="@kbn/ml-agg-utils"/> | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 91 | 2 | 61 | 0 | | <DocLink id="kibKbnMlDatePickerPluginApi" text="@kbn/ml-date-picker"/> | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 52 | 0 | 4 | 0 | | <DocLink id="kibKbnMlIsDefinedPluginApi" text="@kbn/ml-is-defined"/> | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 2 | 0 | 0 | 0 | | <DocLink id="kibKbnMlIsPopulatedObjectPluginApi" text="@kbn/ml-is-populated-object"/> | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 3 | 0 | 2 | 0 | | <DocLink id="kibKbnMlLocalStoragePluginApi" text="@kbn/ml-local-storage"/> | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 5 | 0 | 3 | 0 | | <DocLink id="kibKbnMlNestedPropertyPluginApi" text="@kbn/ml-nested-property"/> | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 8 | 2 | 8 | 0 | | <DocLink id="kibKbnMlQueryUtilsPluginApi" text="@kbn/ml-query-utils"/> | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 10 | 0 | 0 | 0 | +| <DocLink id="kibKbnMlRandomSamplerUtilsPluginApi" text="@kbn/ml-random-sampler-utils"/> | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 5 | 0 | 0 | 0 | | <DocLink id="kibKbnMlRouteUtilsPluginApi" text="@kbn/ml-route-utils"/> | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 5 | 0 | 0 | 0 | | <DocLink id="kibKbnMlStringHashPluginApi" text="@kbn/ml-string-hash"/> | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 2 | 0 | 1 | 0 | | <DocLink id="kibKbnMlTrainedModelsUtilsPluginApi" text="@kbn/ml-trained-models-utils"/> | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 8 | 1 | 8 | 0 | @@ -467,7 +469,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | <DocLink id="kibKbnSecuritysolutionExceptionListComponentsPluginApi" text="@kbn/securitysolution-exception-list-components"/> | [@elastic/security-solution-platform](https://github.com/orgs/elastic/teams/security-solution-platform) | - | 104 | 0 | 93 | 1 | | <DocLink id="kibKbnSecuritysolutionGroupingPluginApi" text="@kbn/securitysolution-grouping"/> | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 20 | 0 | 15 | 4 | | <DocLink id="kibKbnSecuritysolutionHookUtilsPluginApi" text="@kbn/securitysolution-hook-utils"/> | [@elastic/security-solution-platform](https://github.com/orgs/elastic/teams/security-solution-platform) | - | 15 | 0 | 7 | 0 | -| <DocLink id="kibKbnSecuritysolutionIoTsAlertingTypesPluginApi" text="@kbn/securitysolution-io-ts-alerting-types"/> | [@elastic/security-solution-platform](https://github.com/orgs/elastic/teams/security-solution-platform) | - | 140 | 0 | 121 | 0 | +| <DocLink id="kibKbnSecuritysolutionIoTsAlertingTypesPluginApi" text="@kbn/securitysolution-io-ts-alerting-types"/> | [@elastic/security-solution-platform](https://github.com/orgs/elastic/teams/security-solution-platform) | - | 141 | 0 | 122 | 0 | | <DocLink id="kibKbnSecuritysolutionIoTsListTypesPluginApi" text="@kbn/securitysolution-io-ts-list-types"/> | [@elastic/security-solution-platform](https://github.com/orgs/elastic/teams/security-solution-platform) | - | 516 | 1 | 503 | 0 | | <DocLink id="kibKbnSecuritysolutionIoTsTypesPluginApi" text="@kbn/securitysolution-io-ts-types"/> | [@elastic/security-solution-platform](https://github.com/orgs/elastic/teams/security-solution-platform) | - | 65 | 0 | 36 | 0 | | <DocLink id="kibKbnSecuritysolutionIoTsUtilsPluginApi" text="@kbn/securitysolution-io-ts-utils"/> | [@elastic/security-solution-platform](https://github.com/orgs/elastic/teams/security-solution-platform) | - | 28 | 0 | 21 | 0 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index d677805b28784..0188ba8d0b55d 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: 2023-04-11 +date: 2023-04-12 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 5a4b8cb1623a5..b8b70da1028e2 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index 4c82514fedec6..f2e32360319d5 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: 2023-04-11 +date: 2023-04-12 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 57b9897067650..5a3587ee2f9b9 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: 2023-04-11 +date: 2023-04-12 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 7bec48e672675..ac4bf0b88d04d 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: 2023-04-11 +date: 2023-04-12 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 755764d6b7f2d..a7e5c630e77ab 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: 2023-04-11 +date: 2023-04-12 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 6a3cfeb26fc74..2d27b50485b5a 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: 2023-04-11 +date: 2023-04-12 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 65ae82b638b67..5516f9dc5c929 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: 2023-04-11 +date: 2023-04-12 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 ca7f83457d863..5b3be83040f67 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: 2023-04-11 +date: 2023-04-12 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 0cb2411d25e60..5e20421ebb1bb 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: 2023-04-11 +date: 2023-04-12 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 2ec47e269264a..b1673b54719e4 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: 2023-04-11 +date: 2023-04-12 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 e5860724380eb..cd34a0f54e703 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: 2023-04-11 +date: 2023-04-12 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 2eeeeec7a3087..7e5afa4729b26 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: 2023-04-11 +date: 2023-04-12 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 8a520b62c98c7..e8f67189f3c08 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: 2023-04-11 +date: 2023-04-12 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 d803cb7e80d10..7c7a8145f7207 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/security.mdx b/api_docs/security.mdx index fafb92ccf8e49..20a8de778d363 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: 2023-04-11 +date: 2023-04-12 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 5ebab4a020d6d..febaf145c0154 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index 1549e2cf23e99..70f55555251d7 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: 2023-04-11 +date: 2023-04-12 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 fc1e71ae18a7d..b4498b12ef8a2 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index e53af0c852485..13ac0233e0b33 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: 2023-04-11 +date: 2023-04-12 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 204dcd5c104a5..9d69a50a2bc47 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: 2023-04-11 +date: 2023-04-12 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 e7c56b7689ecd..c3f0919e89288 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: 2023-04-11 +date: 2023-04-12 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 b94983662db4e..fe512463bd661 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: 2023-04-11 +date: 2023-04-12 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 e966492033bba..b38fd371818bd 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: 2023-04-11 +date: 2023-04-12 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 c99c93128ea85..aee3ac9d4aea4 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: 2023-04-11 +date: 2023-04-12 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 58df8060b8f29..6786d45c73e4c 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: 2023-04-11 +date: 2023-04-12 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 695c74ad94ad3..c0c2b2a0c4926 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: 2023-04-11 +date: 2023-04-12 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 61bdb8a62ec76..48e1d4bc0ae7b 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index 025735e476222..af4a168bd6b3f 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: 2023-04-11 +date: 2023-04-12 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 80fc0064d9483..9d1c4dcf8052a 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: 2023-04-11 +date: 2023-04-12 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 2bbcfabad1dd6..b1c5fcb82fd58 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.devdocs.json b/api_docs/triggers_actions_ui.devdocs.json index 5a52140b96c40..e747db4d48838 100644 --- a/api_docs/triggers_actions_ui.devdocs.json +++ b/api_docs/triggers_actions_ui.devdocs.json @@ -4625,7 +4625,7 @@ "label": "setRuleProperty", "description": [], "signature": [ - "<Prop extends \"id\" | \"params\" | \"consumer\" | \"name\" | \"actions\" | \"tags\" | \"enabled\" | \"schedule\" | \"mapped_params\" | \"scheduledTaskId\" | \"createdBy\" | \"updatedBy\" | \"createdAt\" | \"updatedAt\" | \"apiKeyOwner\" | \"throttle\" | \"muteAll\" | \"notifyWhen\" | \"mutedInstanceIds\" | \"executionStatus\" | \"monitoring\" | \"snoozeSchedule\" | \"activeSnoozes\" | \"isSnoozedUntil\" | \"lastRun\" | \"nextRun\" | \"revision\" | \"running\" | \"viewInAppRelativeUrl\" | \"ruleTypeId\">(key: Prop, value: ", + "<Prop extends \"id\" | \"params\" | \"consumer\" | \"name\" | \"actions\" | \"tags\" | \"enabled\" | \"schedule\" | \"mapped_params\" | \"scheduledTaskId\" | \"createdBy\" | \"updatedBy\" | \"createdAt\" | \"updatedAt\" | \"apiKeyOwner\" | \"apiKeyCreatedByUser\" | \"throttle\" | \"muteAll\" | \"notifyWhen\" | \"mutedInstanceIds\" | \"executionStatus\" | \"monitoring\" | \"snoozeSchedule\" | \"activeSnoozes\" | \"isSnoozedUntil\" | \"lastRun\" | \"nextRun\" | \"revision\" | \"running\" | \"viewInAppRelativeUrl\" | \"ruleTypeId\">(key: Prop, value: ", "SanitizedRule", "<Params>[Prop] | null) => void" ], diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index e3c96387a91b0..48fe26646adcf 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: 2023-04-11 +date: 2023-04-12 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 e9634d3fa55fc..cdc5f52a84659 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: 2023-04-11 +date: 2023-04-12 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 0a39b64c33e6a..90edf1bc6fc24 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_field_list.mdx b/api_docs/unified_field_list.mdx index a3fb88ef83e7d..a02b2d4991a7f 100644 --- a/api_docs/unified_field_list.mdx +++ b/api_docs/unified_field_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedFieldList title: "unifiedFieldList" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedFieldList plugin -date: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedFieldList'] --- import unifiedFieldListObj from './unified_field_list.devdocs.json'; diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index 48a3ef99c379c..1f3421cd0ba55 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: 2023-04-11 +date: 2023-04-12 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 a1a6e6639b6a6..41e46843d4c16 100644 --- a/api_docs/unified_search.devdocs.json +++ b/api_docs/unified_search.devdocs.json @@ -208,7 +208,7 @@ "section": "def-public.FilterItemsProps", "text": "FilterItemsProps" }, - ", \"indexPatterns\" | \"filters\" | \"readOnly\" | \"onFiltersUpdated\" | \"hiddenPanelOptions\" | \"timeRangeForSuggestionsOverride\"> & React.RefAttributes<React.Component<Pick<", + ", \"indexPatterns\" | \"filters\" | \"readOnly\" | \"filtersForSuggestions\" | \"onFiltersUpdated\" | \"hiddenPanelOptions\" | \"timeRangeForSuggestionsOverride\"> & React.RefAttributes<React.Component<Pick<", { "pluginId": "unifiedSearch", "scope": "public", @@ -216,7 +216,7 @@ "section": "def-public.FilterItemsProps", "text": "FilterItemsProps" }, - ", \"indexPatterns\" | \"filters\" | \"readOnly\" | \"onFiltersUpdated\" | \"hiddenPanelOptions\" | \"timeRangeForSuggestionsOverride\">, any, any>>) => JSX.Element" + ", \"indexPatterns\" | \"filters\" | \"readOnly\" | \"filtersForSuggestions\" | \"onFiltersUpdated\" | \"hiddenPanelOptions\" | \"timeRangeForSuggestionsOverride\">, any, any>>) => JSX.Element" ], "path": "src/plugins/unified_search/public/filter_bar/index.tsx", "deprecated": false, @@ -238,7 +238,7 @@ "section": "def-public.FilterItemsProps", "text": "FilterItemsProps" }, - ", \"indexPatterns\" | \"filters\" | \"readOnly\" | \"onFiltersUpdated\" | \"hiddenPanelOptions\" | \"timeRangeForSuggestionsOverride\"> & React.RefAttributes<React.Component<Pick<", + ", \"indexPatterns\" | \"filters\" | \"readOnly\" | \"filtersForSuggestions\" | \"onFiltersUpdated\" | \"hiddenPanelOptions\" | \"timeRangeForSuggestionsOverride\"> & React.RefAttributes<React.Component<Pick<", { "pluginId": "unifiedSearch", "scope": "public", @@ -246,7 +246,7 @@ "section": "def-public.FilterItemsProps", "text": "FilterItemsProps" }, - ", \"indexPatterns\" | \"filters\" | \"readOnly\" | \"onFiltersUpdated\" | \"hiddenPanelOptions\" | \"timeRangeForSuggestionsOverride\">, any, any>>" + ", \"indexPatterns\" | \"filters\" | \"readOnly\" | \"filtersForSuggestions\" | \"onFiltersUpdated\" | \"hiddenPanelOptions\" | \"timeRangeForSuggestionsOverride\">, any, any>>" ], "path": "src/plugins/unified_search/public/filter_bar/index.tsx", "deprecated": false, @@ -393,7 +393,15 @@ "section": "def-public.TimeHistoryContract", "text": "TimeHistoryContract" }, - " | undefined; customSubmitButton?: React.ReactNode; screenTitle?: string | undefined; showQueryMenu?: boolean | undefined; showQueryInput?: boolean | undefined; showFilterBar?: boolean | undefined; showDatePicker?: boolean | undefined; showAutoRefreshOnly?: boolean | undefined; hiddenFilterPanelOptions?: ", + " | undefined; customSubmitButton?: React.ReactNode; screenTitle?: string | undefined; showQueryMenu?: boolean | undefined; showQueryInput?: boolean | undefined; showFilterBar?: boolean | undefined; showDatePicker?: boolean | undefined; showAutoRefreshOnly?: boolean | undefined; filtersForSuggestions?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; hiddenFilterPanelOptions?: ", "FilterPanelOption", "[] | undefined; isRefreshPaused?: boolean | undefined; dateRangeFrom?: string | undefined; dateRangeTo?: string | undefined; showSaveQuery?: boolean | undefined; savedQuery?: ", { @@ -451,7 +459,15 @@ "section": "def-public.SavedQuery", "text": "SavedQuery" }, - ") => void) | undefined; onClearSavedQuery?: (() => void) | undefined; onRefresh?: ((payload: { dateRange: ", + ") => void) | undefined; onTimeRangeChange?: ((payload: { dateRange: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + "; }) => void) | undefined; onClearSavedQuery?: (() => void) | undefined; onRefresh?: ((payload: { dateRange: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -1091,6 +1107,29 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "unifiedSearch", + "id": "def-public.FilterItemsProps.filtersForSuggestions", + "type": "Array", + "tags": [], + "label": "filtersForSuggestions", + "description": [ + "adds additional filters to be used for suggestions" + ], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined" + ], + "path": "src/plugins/unified_search/public/filter_bar/filter_item/filter_items.tsx", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "unifiedSearch", "id": "def-public.FilterItemsProps.hiddenPanelOptions", @@ -1924,6 +1963,29 @@ "path": "src/plugins/unified_search/public/query_string_input/query_string_input.tsx", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "unifiedSearch", + "id": "def-public.QueryStringInputProps.filtersForSuggestions", + "type": "Array", + "tags": [], + "label": "filtersForSuggestions", + "description": [ + "\nAdd additional filters used for suggestions" + ], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined" + ], + "path": "src/plugins/unified_search/public/query_string_input/query_string_input.tsx", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index ae5e48816e92e..3c64dd45b0628 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] --- import unifiedSearchObj from './unified_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 | |-------------------|-----------|------------------------|-----------------| -| 135 | 2 | 100 | 20 | +| 137 | 2 | 100 | 20 | ## Client diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index 563d42c38a815..54fe886feb66c 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.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 | |-------------------|-----------|------------------------|-----------------| -| 135 | 2 | 100 | 20 | +| 137 | 2 | 100 | 20 | ## Client diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index e6eff0c97b7e9..1ffab250449ca 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: 2023-04-11 +date: 2023-04-12 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 03221df91db4e..e49a0f6eb496c 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: 2023-04-11 +date: 2023-04-12 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 d81746bba0f27..edf11aff83a92 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: 2023-04-11 +date: 2023-04-12 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 810acd314e890..a02abbfae55ca 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: 2023-04-11 +date: 2023-04-12 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 6c7eb0d269464..2f194fc584992 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: 2023-04-11 +date: 2023-04-12 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 c1e9e45d69514..e91435c4db51e 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: 2023-04-11 +date: 2023-04-12 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 8e720f6a71dbc..d497fbf340528 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: 2023-04-11 +date: 2023-04-12 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 9229a322661bc..3a1e949278727 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: 2023-04-11 +date: 2023-04-12 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 e2954916cbdab..0c7e523dad941 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: 2023-04-11 +date: 2023-04-12 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 7ab96c61ee688..5d75d3f3c63e5 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: 2023-04-11 +date: 2023-04-12 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 acd9dd3d9bbfa..7389ccc7770df 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: 2023-04-11 +date: 2023-04-12 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 33ff43f4a5c5b..5b5634c0d1b26 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: 2023-04-11 +date: 2023-04-12 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 380f691bbb573..547f70efa6825 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: 2023-04-11 +date: 2023-04-12 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 c8aec2a7a602b..b319aaa4a4c63 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: 2023-04-11 +date: 2023-04-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; From 41170fe64bea9afe58861d29c80e7eb716abb3bf Mon Sep 17 00:00:00 2001 From: Marco Liberati <dej611@users.noreply.github.com> Date: Wed, 12 Apr 2023 09:38:29 +0200 Subject: [PATCH 21/23] [Lens] Enable report sharing (#153429) ## Summary Fixes #130438 This PR introduces the PNG/PDF reporting feature within Lens editor. **Note** each reporting tasks is generating a shortURL SO in addition of the reporting job SO. There's a reusing mechanism but it applies only to the same config within the same session. * [x] Enable reporting for ~~`lens_visualization` type~~ `lens` type * [x] Introduce disabled state within the reporter logic * [x] Extends the logic to support the custom URL types in Lens * [x] Make reporting list page to support `lens_visualization` object type * migrated `lens_visualization` to `lens` and used the app icon * [x] Extends the custom CSS styling to handle specific Lens editor layout * [x] Introduce logic for `renderComplete` within the Lens editor * [x] Loading logic * [x] Trigger `renderComplete` event for the right node * [x] Add `.hide-for-sharing` class where needed * [x] Add the `.stretch-for-sharing` where needed * Improve layout settings to have a better fit of some charts * Maybe this can be addressed as separate issue? * Check the `renderComplete` for the RegionMap external plugin => separate issue * Write tests * [x] Functional tests Reporting page: <img width="1255" alt="Screenshot 2023-03-24 at 15 25 12" src="https://user-images.githubusercontent.com/924948/227552385-1b52a0ae-8902-4972-acf3-323093a7b840.png"> **Note**: at the moment the reporting name follows the CSV naming convention of `unsaved` for unsaved Lens visualizations. The legacy Agg-based editor uses instead a namming pattern as follow: `Visualization <timestamp>.png`. Final results: | Chart type | PNG result | | ------ | ----- | | Stacked bar chart | ![unsaved](https://user-images.githubusercontent.com/924948/226881443-05b862c0-6637-4b7f-a461-160a69f2bb6c.PNG) | | Vertical bar chart | ![unsaved (1)](https://user-images.githubusercontent.com/924948/226881523-10c0e91a-6ca3-4161-bd11-738d5f6465db.PNG) | | Horizontal stacked bar chart | ![unsaved (2)](https://user-images.githubusercontent.com/924948/226881585-06fe2904-cba1-402f-a67c-549ce09cd83e.PNG) | | Horizontal bar chart | ![unsaved (3)](https://user-images.githubusercontent.com/924948/226881619-0d135b19-d401-4b13-934e-b7aa23ab2792.PNG) | | Datatable | ![unsaved (4)](https://user-images.githubusercontent.com/924948/226881716-f7543803-bd00-433a-85bc-09b0a2c2c7c5.PNG) | | Horizontal gauge | ![unsaved (5)](https://user-images.githubusercontent.com/924948/226881766-54fccf0c-3266-411b-ac43-8c37855a44eb.PNG) | | Vertical gauge | ![unsaved (6)](https://user-images.githubusercontent.com/924948/226881981-f3b5e007-2637-476a-ab43-1c5efa5e44e5.PNG) | | Legacy metric | ![unsaved (7)](https://user-images.githubusercontent.com/924948/226882220-0c456c2d-8fc7-470e-94e1-f22e5ddcb052.PNG) | | Metric | ![unsaved (8)](https://user-images.githubusercontent.com/924948/226882283-03f10b5b-fa36-402b-a3e0-70f49b2b5968.PNG) | | Metric with breakdown | ![unsaved (9)](https://user-images.githubusercontent.com/924948/226882347-a4f53dfd-8c43-4432-b4c8-eea879c897d3.PNG) | | Area chart | ![unsaved (10)](https://user-images.githubusercontent.com/924948/226882381-b7a81a05-9163-4582-8892-ef25bd803778.PNG) | | Line chart | ![unsaved (11)](https://user-images.githubusercontent.com/924948/226882736-8ce49e82-31a1-435b-9ef9-19ea8e885993.PNG) | | Bar chart with annotation + reference lines | ![unsaved (13)](https://user-images.githubusercontent.com/924948/226882841-0aeb5863-4ccb-426d-aae3-9e0afe19e599.PNG) | | Heatmap | ![unsaved (14)](https://user-images.githubusercontent.com/924948/226883059-31ab11a2-7d9a-461c-a38c-158b03e916e1.PNG) | | Donut chart | ![unsaved (15)](https://user-images.githubusercontent.com/924948/226883107-e7cd922e-a488-4ab5-add6-6aac8657f295.PNG) | | Pie chart | ![unsaved (17)](https://user-images.githubusercontent.com/924948/226883158-d7f285a6-63e7-4bf5-9839-ee5c48b25e22.PNG) | | Treemap | ![unsaved (18)](https://user-images.githubusercontent.com/924948/226883250-2b770885-6275-4f07-8eee-1a4d98aef974.PNG) | | Mosaic | ![unsaved (16)](https://user-images.githubusercontent.com/924948/226883328-96cd2461-06e5-4995-8d38-1235b8774781.PNG) | | Waffle | ![unsaved (19)](https://user-images.githubusercontent.com/924948/226883373-c2f7e041-f45d-44ac-982c-8355b44e5fbf.PNG) | | Region Map | ![Lens Visualization 2023-03-31T12_47_48 392+02_00](https://user-images.githubusercontent.com/924948/229101825-dc54a9e8-f89b-4901-b7e7-76a983bc3bd0.PNG) | ### 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 - [ ] 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: Stratoula Kalafateli <efstratia.kalafateli@elastic.co> Co-authored-by: Tim Sullivan <tsullivan@users.noreply.github.com> Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../csv_download_provider.tsx | 2 +- .../get_application_user_messages.test.tsx | 6 +- .../get_application_user_messages.tsx | 2 +- .../lens/public/app_plugin/lens_top_nav.tsx | 41 +++++-- .../lens/public/app_plugin/share_action.ts | 37 ++++-- .../editor_frame/frame_layout.tsx | 16 ++- .../editor_frame/state_helpers.ts | 8 +- .../workspace_panel/workspace_panel.test.tsx | 9 +- .../workspace_panel/workspace_panel.tsx | 58 ++++++++- .../workspace_panel_wrapper.tsx | 8 +- .../lens/public/embeddable/embeddable.tsx | 5 +- .../init_middleware/load_initial.ts | 114 +++++++++--------- .../public/state_management/lens_slice.ts | 24 ++-- .../reporting/public/management/utils.ts | 2 + ...screen_capture_panel_content.test.tsx.snap | 6 + .../public/share_context_menu/index.ts | 1 + .../register_pdf_png_reporting.tsx | 12 +- .../components/error_unsaved_work_panel.tsx | 8 +- .../reporting_panel_content.tsx | 9 +- .../server/layouts/preserve_layout.css | 5 + .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - .../apps/lens/group3/lens_reporting.ts | 96 ++++++++++++++- .../test/functional/page_objects/lens_page.ts | 13 +- 25 files changed, 361 insertions(+), 124 deletions(-) diff --git a/x-pack/plugins/lens/public/app_plugin/csv_download_provider/csv_download_provider.tsx b/x-pack/plugins/lens/public/app_plugin/csv_download_provider/csv_download_provider.tsx index 0ab3834909da8..880a8bed3f405 100644 --- a/x-pack/plugins/lens/public/app_plugin/csv_download_provider/csv_download_provider.tsx +++ b/x-pack/plugins/lens/public/app_plugin/csv_download_provider/csv_download_provider.tsx @@ -100,7 +100,7 @@ export const downloadCsvShareProvider = ({ formatFactoryFn, }: DownloadPanelShareOpts): ShareMenuProvider => { const getShareMenuItems = ({ objectType, sharingData, onClose }: ShareContext) => { - if ('lens_visualization' !== objectType) { + if ('lens' !== objectType) { return []; } diff --git a/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.test.tsx b/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.test.tsx index c49ef7f349f18..fa0ed4e21a668 100644 --- a/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.test.tsx +++ b/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.test.tsx @@ -149,7 +149,7 @@ describe('application-level user messages', () => { activeDatasource: { checkIntegrity: jest.fn(() => ['missing_pattern']), } as unknown as Datasource, - activeDatasourceState: { state: {} }, + activeDatasourceState: { isLoading: false, state: {} }, core: createCoreStartWithPermissions(), ...irrelevantProps, }) @@ -166,7 +166,7 @@ describe('application-level user messages', () => { activeDatasource: { checkIntegrity: jest.fn(() => ['missing_pattern']), } as unknown as Datasource, - activeDatasourceState: { state: {} }, + activeDatasourceState: { isLoading: false, state: {} }, // user can go to management, but indexPatterns management is not accessible core: createCoreStartWithPermissions({ navLinks: { management: true }, @@ -188,7 +188,7 @@ describe('application-level user messages', () => { activeDatasource: { checkIntegrity: jest.fn(() => ['missing_pattern']), } as unknown as Datasource, - activeDatasourceState: { state: {} }, + activeDatasourceState: { isLoading: false, state: {} }, // user can't go to management at all core: createCoreStartWithPermissions({ navLinks: { management: false }, diff --git a/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.tsx b/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.tsx index 4a323a4d654b8..b5a2e0fe24def 100644 --- a/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.tsx +++ b/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.tsx @@ -36,7 +36,7 @@ export const getApplicationUserMessages = ({ visualization: VisualizationState | undefined; visualizationMap: VisualizationMap; activeDatasource: Datasource | null | undefined; - activeDatasourceState: { state: unknown } | null; + activeDatasourceState: { isLoading: boolean; state: unknown } | null; dataViews: DataViewsState; core: CoreStart; }): UserMessage[] => { diff --git a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx index 2052fa5d68fe8..9715b8054a7f2 100644 --- a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx +++ b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx @@ -15,6 +15,8 @@ import { getEsQueryConfig } from '@kbn/data-plugin/public'; import type { DataView } from '@kbn/data-views-plugin/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { DataViewPickerProps } from '@kbn/unified-search-plugin/public'; +import moment from 'moment'; +import { LENS_APP_LOCATOR } from '../../common/locator/locator'; import { ENABLE_SQL } from '../../common/constants'; import { LensAppServices, LensTopNavActions, LensTopNavMenuProps } from './types'; import { toggleSettingsMenuOpen } from './settings_menu'; @@ -457,8 +459,9 @@ export const LensTopNavMenu = ({ isSaveable && application.capabilities.dashboard?.showWriteControls ); - const unsavedTitle = i18n.translate('xpack.lens.app.unsavedFilename', { - defaultMessage: 'unsaved', + const defaultLensTitle = i18n.translate('xpack.lens.app.share.defaultDashboardTitle', { + defaultMessage: 'Lens Visualization [{date}]', + values: { date: moment().toISOString(true) }, }); const additionalMenuEntries = useMemo(() => { if (!visualization.activeId) return undefined; @@ -574,13 +577,12 @@ export const LensTopNavMenu = ({ if (!share) { return; } - const sharingData = { - activeData, - csvEnabled, - title: title || unsavedTitle, - }; - const { shareableUrl, savedObjectURL } = await getShareURL( + const { + shareableUrl, + savedObjectURL, + reportingLocatorParams: locatorParams, + } = await getShareURL( shortUrlService, { application, data }, { @@ -593,8 +595,20 @@ export const LensTopNavMenu = ({ visualization, currentDoc, adHocDataViews: adHocDataViews.map((dataView) => dataView.toSpec()), - } + }, + shareUrlEnabled, + isCurrentStateDirty ); + const sharingData = { + activeData, + csvEnabled, + reportingDisabled: !csvEnabled, + title: title || defaultLensTitle, + locatorParams: { + id: LENS_APP_LOCATOR, + params: locatorParams, + }, + }; share.toggleShareContextMenu({ anchorElement, @@ -603,7 +617,7 @@ export const LensTopNavMenu = ({ shareableUrl: shareableUrl || '', shareableUrlForSavedObject: savedObjectURL.href, objectId: currentDoc?.savedObjectId, - objectType: 'lens_visualization', + objectType: 'lens', objectTypeTitle: i18n.translate('xpack.lens.app.share.panelTitle', { defaultMessage: 'visualization', }), @@ -735,7 +749,6 @@ export const LensTopNavMenu = ({ initialContextIsEmbedded, activeData, isSaveable, - shortUrlService, application, getIsByValueMode, savingToLibraryPermitted, @@ -746,7 +759,7 @@ export const LensTopNavMenu = ({ lensInspector, title, share, - unsavedTitle, + shortUrlService, data, filters, query, @@ -756,6 +769,8 @@ export const LensTopNavMenu = ({ visualizationMap, visualization, currentDoc, + adHocDataViews, + defaultLensTitle, isCurrentStateDirty, onAppLeave, runSave, @@ -770,7 +785,6 @@ export const LensTopNavMenu = ({ isOnTextBasedMode, lensStore, theme$, - adHocDataViews, ]); const onQuerySubmitWrapped = useCallback( @@ -1072,6 +1086,7 @@ export const LensTopNavMenu = ({ screenTitle={'lens'} appName={'lens'} displayStyle="detached" + className="hide-for-sharing" /> ); }; diff --git a/x-pack/plugins/lens/public/app_plugin/share_action.ts b/x-pack/plugins/lens/public/app_plugin/share_action.ts index 02b4e8cc29898..55e4b978f015d 100644 --- a/x-pack/plugins/lens/public/app_plugin/share_action.ts +++ b/x-pack/plugins/lens/public/app_plugin/share_action.ts @@ -45,8 +45,7 @@ function getShareURLForSavedObject( ); } -function getShortShareableURL( - shortUrlService: (params: LensAppLocatorParams) => Promise<string>, +export function getLocatorParams( data: LensAppServices['data'], { filters, @@ -57,7 +56,9 @@ function getShortShareableURL( visualizationMap, visualization, adHocDataViews, - }: ShareableConfiguration + currentDoc, + }: ShareableConfiguration, + isDirty: boolean ) { const references = extractReferencesFromState({ activeDatasources: Object.keys(datasourceStates).reduce( @@ -80,7 +81,7 @@ function getShortShareableURL( const serializableDatasourceStates = datasourceStates as LensAppState['datasourceStates'] & SerializableRecord; - return shortUrlService({ + const snapshotParams = { filters, query, resolvedDateRange: getResolvedDateRange(data.query.timefilter.timefilter), @@ -90,16 +91,38 @@ function getShortShareableURL( searchSessionId: data.search.session.getSessionId(), references, dataViewSpecs: adHocDataViews, - }); + }; + + return { + shareURL: snapshotParams, + // for reporting use the shorten version when available + reporting: + currentDoc?.savedObjectId && !isDirty + ? { + filters, + query, + resolvedDateRange: getResolvedDateRange(data.query.timefilter.timefilter), + savedObjectId: currentDoc?.savedObjectId, + } + : snapshotParams, + }; } export async function getShareURL( shortUrlService: (params: LensAppLocatorParams) => Promise<string>, services: Pick<LensAppServices, 'application' | 'data'>, - configuration: ShareableConfiguration + configuration: ShareableConfiguration, + shareUrlEnabled: boolean, + isDirty: boolean ) { + const { shareURL: locatorParams, reporting: reportingLocatorParams } = getLocatorParams( + services.data, + configuration, + isDirty + ); return { - shareableUrl: await getShortShareableURL(shortUrlService, services.data, configuration), + shareableUrl: await (shareUrlEnabled ? shortUrlService(locatorParams) : undefined), savedObjectURL: getShareURLForSavedObject(services, configuration.currentDoc), + reportingLocatorParams, }; } diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/frame_layout.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/frame_layout.tsx index a0e068ba9f37f..23fc53ababe9f 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/frame_layout.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/frame_layout.tsx @@ -53,7 +53,7 @@ export function FrameLayout(props: FrameLayoutProps) { aria-labelledby="lns_ChartTitle" > <section - className={classNames('lnsFrameLayout__sidebar lnsFrameLayout__sidebar--left', {})} + className={'lnsFrameLayout__sidebar lnsFrameLayout__sidebar--left hide-for-sharing'} aria-labelledby="dataPanelId" > <EuiScreenReaderOnly> @@ -79,12 +79,18 @@ export function FrameLayout(props: FrameLayoutProps) { </h2> </EuiScreenReaderOnly> {props.workspacePanel} - <div className="lnsFrameLayout__suggestionPanel">{props.suggestionsPanel}</div> + <div className="lnsFrameLayout__suggestionPanel hide-for-sharing"> + {props.suggestionsPanel} + </div> </section> <section - className={classNames('lnsFrameLayout__sidebar lnsFrameLayout__sidebar--right', { - 'lnsFrameLayout__sidebar-isFullscreen': isFullscreen, - })} + className={classNames( + 'lnsFrameLayout__sidebar lnsFrameLayout__sidebar--right', + 'hide-for-sharing', + { + 'lnsFrameLayout__sidebar-isFullscreen': isFullscreen, + } + )} aria-labelledby="configPanel" > <EuiScreenReaderOnly> diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts index cea4597be577a..9a31b98328b53 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts @@ -404,10 +404,14 @@ export async function persistedStateToExpression( export function getMissingIndexPattern( currentDatasource: Datasource | null | undefined, - currentDatasourceState: { state: unknown } | null, + currentDatasourceState: { isLoading: boolean; state: unknown } | null, indexPatterns: IndexPatternMap ) { - if (currentDatasourceState?.state == null || currentDatasource == null) { + if ( + currentDatasourceState?.isLoading || + currentDatasourceState?.state == null || + currentDatasource == null + ) { return []; } const missingIds = currentDatasource.checkIntegrity(currentDatasourceState.state, indexPatterns); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx index 1d118a6f869c7..910e3970e5c15 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx @@ -72,8 +72,8 @@ const defaultProps = { getSuggestionForField: () => undefined, lensInspector: getLensInspectorService(inspectorPluginMock.createStartContract()), toggleFullscreen: jest.fn(), - getUserMessages: () => [], - addUserMessages: () => () => {}, + getUserMessages: jest.fn(() => []), + addUserMessages: jest.fn(() => () => {}), }; const toExpr = ( @@ -728,10 +728,10 @@ describe('workspace_panel', () => { const mounted = await mountWithProvider( <WorkspacePanel {...defaultProps} + getUserMessages={getUserMessages} datasourceMap={{ testDatasource: mockDatasource, }} - getUserMessages={getUserMessages} /> ); instance = mounted.instance; @@ -752,11 +752,12 @@ describe('workspace_panel', () => { // but not yet applied their changes let userMessages = [] as UserMessage[]; + const getUserMessageFn = jest.fn(() => userMessages); const mounted = await mountWithProvider( <WorkspacePanel {...defaultProps} - getUserMessages={() => userMessages} + getUserMessages={getUserMessageFn} datasourceMap={{ testDatasource: mockDatasource, }} diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index a0769fc18350f..f4571b952abf6 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -624,6 +624,26 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ ); }); +function useReportingState(errors: UserMessage[]): { + isRenderComplete: boolean; + hasDynamicError: boolean; + setIsRenderComplete: (state: boolean) => void; + setDynamicError: (state: boolean) => void; + nodeRef: React.RefObject<HTMLDivElement>; +} { + const [isRenderComplete, setIsRenderComplete] = useState(Boolean(errors?.length)); + const [hasDynamicError, setDynamicError] = useState(false); + const nodeRef = useRef<HTMLDivElement>(null); + + useEffect(() => { + if (isRenderComplete && nodeRef.current) { + nodeRef.current.dispatchEvent(new CustomEvent('renderComplete', { bubbles: true })); + } + }, [isRenderComplete, errors]); + + return { isRenderComplete, setIsRenderComplete, hasDynamicError, setDynamicError, nodeRef }; +} + export const VisualizationWrapper = ({ expression, framePublicAPI, @@ -654,6 +674,9 @@ export const VisualizationWrapper = ({ onData$: (data: unknown, adapters?: Partial<DefaultInspectorAdapters>) => void; }) => { const context = useLensSelector(selectExecutionContext); + // Used for reporting + const { isRenderComplete, hasDynamicError, setIsRenderComplete, setDynamicError, nodeRef } = + useReportingState(errors); const searchContext: ExecutionContextSearch = useMemo( () => ({ query: context.query, @@ -668,7 +691,7 @@ export const VisualizationWrapper = ({ ); const searchSessionId = useLensSelector(selectSearchSessionId); - if (errors?.length) { + if (errors.length) { const showExtraErrorsAction = !localState.expandError && errors.length > 1 ? ( <EuiButtonEmpty @@ -690,7 +713,14 @@ export const VisualizationWrapper = ({ const [firstMessage, ...rest] = errors; return ( - <EuiFlexGroup> + <EuiFlexGroup + data-shared-items-container + data-render-complete={true} + data-shared-item="" + data-render-error={i18n.translate('xpack.lens.editorFrame.configurationFailureErrors', { + defaultMessage: `A configuration error occurred`, + })} + > <EuiFlexItem> <EuiEmptyPrompt actions={showExtraErrorsAction} @@ -719,7 +749,20 @@ export const VisualizationWrapper = ({ } return ( - <div className="lnsExpressionRenderer"> + <div + className="lnsExpressionRenderer" + data-shared-items-container + data-render-complete={isRenderComplete} + data-shared-item="" + data-render-error={ + hasDynamicError + ? i18n.translate('xpack.lens.editorFrame.dataFailure', { + defaultMessage: `An error occurred when loading data.`, + }) + : undefined + } + ref={nodeRef} + > <ExpressionRendererComponent className="lnsExpressionRenderer__component" padding="m" @@ -729,7 +772,10 @@ export const VisualizationWrapper = ({ onEvent={onEvent} hasCompatibleActions={hasCompatibleActions} onData$={onData$} - onRender$={onRender$} + onRender$={() => { + setIsRenderComplete(true); + onRender$(); + }} inspectorAdapters={lensInspector.adapters} executionContext={executionContext} renderMode="edit" @@ -741,6 +787,10 @@ export const VisualizationWrapper = ({ ? [errorMessage] : []; + if (!hasDynamicError) { + setDynamicError(true); + } + return ( <EuiFlexGroup> <EuiFlexItem> diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx index 8e8a914a15bff..6b61e4dd374c5 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx @@ -91,7 +91,11 @@ export function WorkspacePanelWrapper({ mainProps={{ component: 'div' } as unknown as {}} > {!(isFullscreen && (autoApplyEnabled || userMessages?.length)) && ( - <EuiPageTemplate.Section paddingSize="none" color="transparent"> + <EuiPageTemplate.Section + paddingSize="none" + color="transparent" + className="hide-for-sharing" + > <EuiFlexGroup alignItems="flexEnd" gutterSize="s" @@ -170,7 +174,7 @@ export function WorkspacePanelWrapper({ contentProps={{ className: 'lnsWorkspacePanelWrapper__content', }} - className={classNames('lnsWorkspacePanelWrapper', { + className={classNames('lnsWorkspacePanelWrapper stretch-for-sharing', { 'lnsWorkspacePanelWrapper--fullscreen': isFullscreen, })} color="transparent" diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.tsx index 0f8594347a34b..882638fac9684 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable.tsx @@ -609,7 +609,10 @@ export class Embeddable }, visualizationMap: this.deps.visualizationMap, activeDatasource: this.activeDatasource, - activeDatasourceState: { state: this.activeDatasourceState }, + activeDatasourceState: { + isLoading: Boolean(this.activeDatasourceState), + state: this.activeDatasourceState, + }, dataViews: { indexPatterns: this.indexPatterns, indexPatternRefs: this.indexPatternRefs, // TODO - are these actually used? diff --git a/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts b/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts index 97c08a1ad3258..f979b90d3c5da 100644 --- a/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts +++ b/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts @@ -121,11 +121,7 @@ export function loadInitial( if (initialContext && 'query' in initialContext) { activeDatasourceId = 'textBased'; } - if (initialStateFromLocator) { - const locatorReferences = - 'references' in initialStateFromLocator ? initialStateFromLocator.references : undefined; - const newFilters = initialStateFromLocator.filters ? cloneDeep(initialStateFromLocator.filters) : undefined; @@ -141,61 +137,67 @@ export function loadInitial( }; data.query.timefilter.timefilter.setTime(newTimeRange); } + // URL Reporting is using the locator params but also passing the savedObjectId + // so be sure to not go here as there's no full snapshot URL + if (!initialInput) { + const locatorReferences = + 'references' in initialStateFromLocator ? initialStateFromLocator.references : undefined; - return initializeSources( - { - datasourceMap, - visualizationMap, - visualizationState: emptyState.visualization, - datasourceStates: emptyState.datasourceStates, - initialContext, - adHocDataViews: - lens.persistedDoc?.state.adHocDataViews || initialStateFromLocator.dataViewSpecs, - references: locatorReferences, - ...loaderSharedArgs, - }, - { - isFullEditor: true, - } - ) - .then(({ datasourceStates, visualizationState, indexPatterns, indexPatternRefs }) => { - const currentSessionId = - initialStateFromLocator?.searchSessionId || data.search.session.getSessionId(); - store.dispatch( - setState({ - isSaveable: true, - filters: initialStateFromLocator.filters || data.query.filterManager.getFilters(), - query: initialStateFromLocator.query || emptyState.query, - searchSessionId: currentSessionId, - activeDatasourceId: emptyState.activeDatasourceId, - visualization: { - activeId: emptyState.visualization.activeId, - state: visualizationState, - }, - dataViews: getInitialDataViewsObject(indexPatterns, indexPatternRefs), - datasourceStates: Object.entries(datasourceStates).reduce( - (state, [datasourceId, datasourceState]) => ({ - ...state, - [datasourceId]: { - ...datasourceState, - isLoading: false, - }, - }), - {} - ), - isLoading: false, - }) - ); - - if (autoApplyDisabled) { - store.dispatch(disableAutoApply()); + return initializeSources( + { + datasourceMap, + visualizationMap, + visualizationState: emptyState.visualization, + datasourceStates: emptyState.datasourceStates, + initialContext, + adHocDataViews: + lens.persistedDoc?.state.adHocDataViews || initialStateFromLocator.dataViewSpecs, + references: locatorReferences, + ...loaderSharedArgs, + }, + { + isFullEditor: true, } - }) - .catch((e: { message: string }) => { - notifications.toasts.addDanger({ - title: e.message, + ) + .then(({ datasourceStates, visualizationState, indexPatterns, indexPatternRefs }) => { + const currentSessionId = + initialStateFromLocator?.searchSessionId || data.search.session.getSessionId(); + store.dispatch( + setState({ + isSaveable: true, + filters: initialStateFromLocator.filters || data.query.filterManager.getFilters(), + query: initialStateFromLocator.query || emptyState.query, + searchSessionId: currentSessionId, + activeDatasourceId: emptyState.activeDatasourceId, + visualization: { + activeId: emptyState.visualization.activeId, + state: visualizationState, + }, + dataViews: getInitialDataViewsObject(indexPatterns, indexPatternRefs), + datasourceStates: Object.entries(datasourceStates).reduce( + (state, [datasourceId, datasourceState]) => ({ + ...state, + [datasourceId]: { + ...datasourceState, + isLoading: false, + }, + }), + {} + ), + isLoading: false, + }) + ); + + if (autoApplyDisabled) { + store.dispatch(disableAutoApply()); + } + }) + .catch((e: { message: string }) => { + notifications.toasts.addDanger({ + title: e.message, + }); }); - }); + } } if ( diff --git a/x-pack/plugins/lens/public/state_management/lens_slice.ts b/x-pack/plugins/lens/public/state_management/lens_slice.ts index 5f00eed48005f..3663daef8fcae 100644 --- a/x-pack/plugins/lens/public/state_management/lens_slice.ts +++ b/x-pack/plugins/lens/public/state_management/lens_slice.ts @@ -62,13 +62,21 @@ export const getPreloadedState = ({ }: LensStoreDeps) => { const initialDatasourceId = getInitialDatasourceId(datasourceMap); const datasourceStates: LensAppState['datasourceStates'] = {}; + // Initialize an empty datasourceStates for each datasource + if (initialDatasourceId) { + Object.keys(datasourceMap).forEach((datasourceId) => { + datasourceStates[datasourceId] = { + state: null, + isLoading: true, + }; + }); + } if (initialStateFromLocator) { + // if anything is passed via locator then populate the empty state if ('datasourceStates' in initialStateFromLocator) { Object.keys(datasourceMap).forEach((datasourceId) => { - datasourceStates[datasourceId] = { - state: initialStateFromLocator.datasourceStates[datasourceId], - isLoading: true, - }; + datasourceStates[datasourceId].state = + initialStateFromLocator.datasourceStates[datasourceId]; }); } return { @@ -82,14 +90,6 @@ export const getPreloadedState = ({ datasourceStates, }; } - if (initialDatasourceId) { - Object.keys(datasourceMap).forEach((datasourceId) => { - datasourceStates[datasourceId] = { - state: null, - isLoading: true, - }; - }); - } const state = { ...initialState, diff --git a/x-pack/plugins/reporting/public/management/utils.ts b/x-pack/plugins/reporting/public/management/utils.ts index 1b3ed519b89ae..87e49c2054f92 100644 --- a/x-pack/plugins/reporting/public/management/utils.ts +++ b/x-pack/plugins/reporting/public/management/utils.ts @@ -25,6 +25,8 @@ export const guessAppIconTypeFromObjectType = (type: string): IconType => { return 'visualizeApp'; case 'canvas workpad': return 'canvasApp'; + case 'lens': + return 'lensApp'; default: return 'apps'; } diff --git a/x-pack/plugins/reporting/public/share_context_menu/__snapshots__/screen_capture_panel_content.test.tsx.snap b/x-pack/plugins/reporting/public/share_context_menu/__snapshots__/screen_capture_panel_content.test.tsx.snap index fe178b03de95d..14d73e5df7877 100644 --- a/x-pack/plugins/reporting/public/share_context_menu/__snapshots__/screen_capture_panel_content.test.tsx.snap +++ b/x-pack/plugins/reporting/public/share_context_menu/__snapshots__/screen_capture_panel_content.test.tsx.snap @@ -95,6 +95,7 @@ exports[`ScreenCapturePanelContent properly renders a view with "canvas" layout /> <div class="euiAccordion" + data-test-subj="shareReportingAdvancedOptionsButton" > <div class="euiAccordion__triggerWrapper emotion-euiAccordion__triggerWrapper" @@ -156,6 +157,7 @@ exports[`ScreenCapturePanelContent properly renders a view with "canvas" layout /> <div class="euiPanel euiPanel--danger euiPanel--paddingSmall euiCallOut euiCallOut--danger emotion-euiPanel-none-s-danger-euiCallOut" + data-test-subj="shareReportingUnsavedState" > <p class="euiTitle euiCallOutHeader__title emotion-euiTitle-xxs-euiCallOutHeader-danger" @@ -287,6 +289,7 @@ exports[`ScreenCapturePanelContent properly renders a view with "print" layout o /> <div class="euiAccordion" + data-test-subj="shareReportingAdvancedOptionsButton" > <div class="euiAccordion__triggerWrapper emotion-euiAccordion__triggerWrapper" @@ -348,6 +351,7 @@ exports[`ScreenCapturePanelContent properly renders a view with "print" layout o /> <div class="euiPanel euiPanel--danger euiPanel--paddingSmall euiCallOut euiCallOut--danger emotion-euiPanel-none-s-danger-euiCallOut" + data-test-subj="shareReportingUnsavedState" > <p class="euiTitle euiCallOutHeader__title emotion-euiTitle-xxs-euiCallOutHeader-danger" @@ -420,6 +424,7 @@ exports[`ScreenCapturePanelContent renders the default view properly 1`] = ` /> <div class="euiAccordion" + data-test-subj="shareReportingAdvancedOptionsButton" > <div class="euiAccordion__triggerWrapper emotion-euiAccordion__triggerWrapper" @@ -481,6 +486,7 @@ exports[`ScreenCapturePanelContent renders the default view properly 1`] = ` /> <div class="euiPanel euiPanel--danger euiPanel--paddingSmall euiCallOut euiCallOut--danger emotion-euiPanel-none-s-danger-euiCallOut" + data-test-subj="shareReportingUnsavedState" > <p class="euiTitle euiCallOutHeader__title emotion-euiTitle-xxs-euiCallOutHeader-danger" diff --git a/x-pack/plugins/reporting/public/share_context_menu/index.ts b/x-pack/plugins/reporting/public/share_context_menu/index.ts index 1d3760edd2625..b9fad615f6a39 100644 --- a/x-pack/plugins/reporting/public/share_context_menu/index.ts +++ b/x-pack/plugins/reporting/public/share_context_menu/index.ts @@ -28,6 +28,7 @@ export interface ExportPanelShareOpts { export interface ReportingSharingData { title: string; layout: LayoutParams; + reportingDisabled?: boolean; [key: string]: unknown; } diff --git a/x-pack/plugins/reporting/public/share_context_menu/register_pdf_png_reporting.tsx b/x-pack/plugins/reporting/public/share_context_menu/register_pdf_png_reporting.tsx index 167ff3311f50a..7efea3195b76a 100644 --- a/x-pack/plugins/reporting/public/share_context_menu/register_pdf_png_reporting.tsx +++ b/x-pack/plugins/reporting/public/share_context_menu/register_pdf_png_reporting.tsx @@ -71,6 +71,7 @@ export const reportingScreenshotShareProvider = ({ isDirty, onClose, shareableUrl, + shareableUrlForSavedObject, ...shareOpts }: ShareContext) => { const { enableLinks, showLinks, message } = checkLicense(license.check('reporting', 'gold')); @@ -95,8 +96,9 @@ export const reportingScreenshotShareProvider = ({ if (!licenseHasScreenshotReporting) { return []; } + const isSupportedType = ['dashboard', 'visualization', 'lens'].includes(objectType); - if (!['dashboard', 'visualization'].includes(objectType)) { + if (!isSupportedType) { return []; } @@ -104,7 +106,7 @@ export const reportingScreenshotShareProvider = ({ return []; } - if (objectType === 'visualize' && !capabilityHasVisualizeScreenshotReporting) { + if (isSupportedType && !capabilityHasVisualizeScreenshotReporting) { return []; } @@ -116,7 +118,7 @@ export const reportingScreenshotShareProvider = ({ }); const jobProviderOptions: JobParamsProviderOptions = { - shareableUrl, + shareableUrl: isDirty ? shareableUrl : shareableUrlForSavedObject ?? shareableUrl, objectType, sharingData, }; @@ -131,7 +133,7 @@ export const reportingScreenshotShareProvider = ({ name: pngPanelTitle, icon: 'document', toolTipContent: licenseToolTipContent, - disabled: licenseDisabled, + disabled: licenseDisabled || sharingData.reportingDisabled, ['data-test-subj']: 'PNGReports', sortOrder: 10, }, @@ -166,7 +168,7 @@ export const reportingScreenshotShareProvider = ({ name: pdfPanelTitle, icon: 'document', toolTipContent: licenseToolTipContent, - disabled: licenseDisabled, + disabled: licenseDisabled || sharingData.reportingDisabled, ['data-test-subj']: 'PDFReports', sortOrder: 10, }, diff --git a/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/components/error_unsaved_work_panel.tsx b/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/components/error_unsaved_work_panel.tsx index b9fa0c5ac3818..75a6a8ba35626 100644 --- a/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/components/error_unsaved_work_panel.tsx +++ b/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/components/error_unsaved_work_panel.tsx @@ -18,7 +18,13 @@ const i18nTexts = { export const ErrorUnsavedWorkPanel: FunctionComponent = () => { return ( - <EuiCallOut size="s" title={i18nTexts.title} iconType="warning" color="danger"> + <EuiCallOut + size="s" + title={i18nTexts.title} + iconType="warning" + color="danger" + data-test-subj="shareReportingUnsavedState" + > <EuiText size="s"> <p> <FormattedMessage diff --git a/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/reporting_panel_content.tsx b/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/reporting_panel_content.tsx index a798c8ff17c25..9102802f5d79e 100644 --- a/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/reporting_panel_content.tsx +++ b/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/reporting_panel_content.tsx @@ -135,7 +135,13 @@ class ReportingPanelContentUi extends Component<Props, State> { return ( <EuiCopy textToCopy={this.state.absoluteUrl} anchorClassName="eui-displayBlock"> {(copy) => ( - <EuiButton color={isUnsaved ? 'warning' : 'primary'} fullWidth onClick={copy} size="s"> + <EuiButton + color={isUnsaved ? 'warning' : 'primary'} + fullWidth + onClick={copy} + size="s" + data-test-subj="shareReportingCopyURL" + > <FormattedMessage id="xpack.reporting.panelContent.copyUrlButtonLabel" defaultMessage="Copy POST URL" @@ -200,6 +206,7 @@ class ReportingPanelContentUi extends Component<Props, State> { defaultMessage: 'Advanced options', })} paddingSize="none" + data-test-subj="shareReportingAdvancedOptionsButton" > <EuiSpacer size="s" /> <EuiText size="s"> diff --git a/x-pack/plugins/screenshotting/server/layouts/preserve_layout.css b/x-pack/plugins/screenshotting/server/layouts/preserve_layout.css index 7b692881d5bde..1e88c4efad953 100644 --- a/x-pack/plugins/screenshotting/server/layouts/preserve_layout.css +++ b/x-pack/plugins/screenshotting/server/layouts/preserve_layout.css @@ -7,6 +7,11 @@ display: none !important; } +/* some elements needs to be stretched to be shared */ +.stretch-for-sharing { + margin: 0px; +} + /** * Global overrides */ diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index ceb82974f0d56..c608004769db8 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -19254,7 +19254,6 @@ "xpack.lens.app.showUnderlyingDataMultipleLayers": "Impossible d’afficher les données sous-jacentes pour les visualisations avec plusieurs calques.", "xpack.lens.app.showUnderlyingDataNoData": "La visualisation ne comprend aucune donnée disponible à afficher.", "xpack.lens.app.showUnderlyingDataTimeShifts": "Impossible d’afficher les données sous-jacentes lorsqu’un décalage temporel est configuré.", - "xpack.lens.app.unsavedFilename": "non enregistré", "xpack.lens.app.unsavedWorkConfirmBtn": "Abandonner les modifications", "xpack.lens.app.unsavedWorkMessage": "Quitter Lens avec un travail non enregistré ?", "xpack.lens.app.unsavedWorkTitle": "Modifications non enregistrées", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 89a92f9c4ad21..0e837ce9b8129 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -19254,7 +19254,6 @@ "xpack.lens.app.showUnderlyingDataMultipleLayers": "複数レイヤーのビジュアライゼーションでは、基本データを表示できません", "xpack.lens.app.showUnderlyingDataNoData": "ビジュアライゼーションには表示するデータがありません", "xpack.lens.app.showUnderlyingDataTimeShifts": "時間シフトが構成されているときには基本データを表示できません", - "xpack.lens.app.unsavedFilename": "未保存", "xpack.lens.app.unsavedWorkConfirmBtn": "変更を破棄", "xpack.lens.app.unsavedWorkMessage": "作業内容を保存せずに、Lens から移動しますか?", "xpack.lens.app.unsavedWorkTitle": "保存されていない変更", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 2f50f22e0ce3b..3dde850f07d85 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -19255,7 +19255,6 @@ "xpack.lens.app.showUnderlyingDataMultipleLayers": "无法显示具有多个图层的可视化的底层数据", "xpack.lens.app.showUnderlyingDataNoData": "可视化没有可显示的可用数据", "xpack.lens.app.showUnderlyingDataTimeShifts": "配置了时间偏移时无法显示底层数据", - "xpack.lens.app.unsavedFilename": "未保存", "xpack.lens.app.unsavedWorkConfirmBtn": "放弃更改", "xpack.lens.app.unsavedWorkMessage": "离开有未保存工作的 Lens?", "xpack.lens.app.unsavedWorkTitle": "未保存的更改", diff --git a/x-pack/test/functional/apps/lens/group3/lens_reporting.ts b/x-pack/test/functional/apps/lens/group3/lens_reporting.ts index dd54475efff32..853173698ad3e 100644 --- a/x-pack/test/functional/apps/lens/group3/lens_reporting.ts +++ b/x-pack/test/functional/apps/lens/group3/lens_reporting.ts @@ -9,11 +9,20 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { - const PageObjects = getPageObjects(['common', 'dashboard', 'reporting', 'timePicker']); + const PageObjects = getPageObjects([ + 'common', + 'dashboard', + 'lens', + 'reporting', + 'timePicker', + 'visualize', + ]); const es = getService('es'); + const testSubjects = getService('testSubjects'); const kibanaServer = getService('kibanaServer'); const listingTable = getService('listingTable'); const security = getService('security'); + const browser = getService('browser'); describe('lens reporting', () => { before(async () => { @@ -25,6 +34,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { [ 'test_logstash_reader', 'global_dashboard_read', + 'global_visualize_all', 'reporting_user', // NOTE: the built-in role granting full reporting access is deprecated. See xpack.reporting.roles.enabled ], { skipBrowserRefresh: true } @@ -50,5 +60,89 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const url = await PageObjects.reporting.getReportURL(60000); expect(url).to.be.ok(); }); + + for (const type of ['PNG', 'PDF'] as const) { + describe(`${type} report`, () => { + it(`should not allow to download reports for incomplete visualization`, async () => { + await PageObjects.visualize.gotoVisualizationLandingPage(); + await PageObjects.visualize.navigateToNewVisualization(); + await PageObjects.visualize.clickVisType('lens'); + await PageObjects.lens.goToTimeRange(); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_xDimensionPanel > lns-empty-dimension', + operation: 'date_histogram', + field: '@timestamp', + }); + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension', + operation: 'average', + field: 'bytes', + }); + + // now remove a dimension to make it incomplete + await PageObjects.lens.removeDimension('lnsXY_yDimensionPanel'); + // open the share menu and check that reporting is disabled + await PageObjects.lens.clickShareMenu(); + + expect(await PageObjects.lens.isShareActionEnabled(`${type}Reports`)); + }); + + it(`should be able to download report of the current visualization`, async () => { + // make the configuration complete + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension', + operation: 'average', + field: 'bytes', + }); + + await PageObjects.lens.openReportingShare(type); + await PageObjects.reporting.clickGenerateReportButton(); + const url = await PageObjects.reporting.getReportURL(60000); + expect(url).to.be.ok(); + }); + + it(`should show a warning message for curl reporting of unsaved visualizations`, async () => { + await PageObjects.lens.openReportingShare(type); + await testSubjects.click('shareReportingAdvancedOptionsButton'); + await testSubjects.existOrFail('shareReportingUnsavedState'); + expect(await testSubjects.getVisibleText('shareReportingUnsavedState')).to.eql( + 'Unsaved work\nSave your work before copying this URL.' + ); + }); + + it(`should enable curl reporting if the visualization is saved`, async () => { + await PageObjects.lens.save(`ASavedVisualizationToShareIn${type}`); + + await PageObjects.lens.openReportingShare(type); + await testSubjects.click('shareReportingAdvancedOptionsButton'); + await testSubjects.existOrFail('shareReportingCopyURL'); + expect(await testSubjects.getVisibleText('shareReportingCopyURL')).to.eql( + 'Copy POST URL' + ); + }); + + it(`should produce a valid URL for reporting`, async () => { + await PageObjects.reporting.clickGenerateReportButton(); + await PageObjects.reporting.getReportURL(60000); + // navigate to the reporting page + await PageObjects.common.navigateToUrl('management', '/insightsAndAlerting'); + await testSubjects.click('reporting'); + // find the latest Lens report + await testSubjects.click('reportJobRow > euiCollapsedItemActionsButton'); + // click on Open in Kibana and check that all is ok + await testSubjects.click('reportOpenInKibanaApp'); + + const [reportingWindowHandler, lensWindowHandle] = await browser.getAllWindowHandles(); + await browser.switchToWindow(lensWindowHandle); + // verify some configuration + expect(await PageObjects.lens.getDimensionTriggerText('lnsXY_yDimensionPanel')).to.eql( + 'Average of bytes' + ); + await browser.closeCurrentWindow(); + await browser.switchToWindow(reportingWindowHandler); + }); + }); + } }); } diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index 43bbaf418dc17..a246ef54b8dd6 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -1677,16 +1677,20 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont return await testSubjects.isEnabled('lnsApp_shareButton'); }, - async isShareActionEnabled(action: 'csvDownload' | 'permalinks') { + async isShareActionEnabled(action: 'csvDownload' | 'permalinks' | 'PNGReports' | 'PDFReports') { switch (action) { case 'csvDownload': return await testSubjects.isEnabled('sharePanel-CSVDownload'); case 'permalinks': return await testSubjects.isEnabled('sharePanel-Permalinks'); + default: + return await testSubjects.isEnabled(`sharePanel-${action}`); } }, - async ensureShareMenuIsOpen(action: 'csvDownload' | 'permalinks') { + async ensureShareMenuIsOpen( + action: 'csvDownload' | 'permalinks' | 'PNGReports' | 'PDFReports' + ) { await this.clickShareMenu(); if (!(await testSubjects.exists('shareContextMenu'))) { @@ -1739,6 +1743,11 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont }, value); }, + async openReportingShare(type: 'PNG' | 'PDF') { + await this.ensureShareMenuIsOpen(`${type}Reports`); + await testSubjects.click(`sharePanel-${type}Reports`); + }, + async getCSVContent() { await testSubjects.click('lnsApp_downloadCSVButton'); return await browser.execute< From 0790ec0da21d709e9501f80a5ea1af4a0b9ca941 Mon Sep 17 00:00:00 2001 From: Yan Savitski <yan.savitski@elastic.co> Date: Wed, 12 Apr 2023 11:54:47 +0200 Subject: [PATCH 22/23] [Enterprise Search] [Behavioral analytics] Create dashboard details tables (#154790) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✅ Created logic for fetch explore items ✅ UI for tables ✅ Add tables 'Popular search terms', 'Worse performers', 'Top clicked results', 'Top referrers' <img width="1296" alt="image" src="https://user-images.githubusercontent.com/17390745/231310342-2bc9b776-362e-4d8c-bd1c-0944e94216c9.png"> <img width="1296" alt="image" src="https://user-images.githubusercontent.com/17390745/231310360-831d4f6c-feab-4b94-9d8c-67218d6b0557.png"> <img width="1296" alt="image" src="https://user-images.githubusercontent.com/17390745/231310408-92bda734-6783-433d-a752-99025c30c446.png"> --- ...nalytics_collection_explore_table.test.tsx | 66 ++++ .../analytics_collection_explore_table.tsx | 321 +++++++++++++++++ ...ics_collection_explore_table_logic.test.ts | 149 ++++++++ ...nalytics_collection_explore_table_logic.ts | 333 ++++++++++++++++++ ...nalytics_collection_explore_table_types.ts | 47 +++ .../analytics_collection_overview.tsx | 55 --- .../analytics_collection_chart.test.tsx | 6 +- .../analytics_collection_chart.tsx | 207 +++++------ .../analytics_collection_metric.test.tsx | 0 .../analytics_collection_metric.tsx | 2 +- .../analytics_collection_overview.test.tsx | 39 +- .../analytics_collection_overview.tsx | 128 +++++++ .../analytics_collection_view.tsx | 7 +- 13 files changed, 1174 insertions(+), 186 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table_logic.test.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table_logic.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table_types.ts delete mode 100644 x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview.tsx rename x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/{ => analytics_collection_overview}/analytics_collection_chart.test.tsx (91%) rename x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/{ => analytics_collection_overview}/analytics_collection_chart.tsx (59%) rename x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/{ => analytics_collection_overview}/analytics_collection_metric.test.tsx (100%) rename x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/{ => analytics_collection_overview}/analytics_collection_metric.tsx (99%) rename x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/{ => analytics_collection_overview}/analytics_collection_overview.test.tsx (63%) create mode 100644 x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_overview.tsx diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table.test.tsx new file mode 100644 index 0000000000000..f949639d534a9 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table.test.tsx @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { setMockActions, setMockValues } from '../../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { mount, shallow } from 'enzyme'; + +import { EuiBasicTable, EuiTab } from '@elastic/eui'; + +import { FilterBy } from '../../../utils/get_formula_by_filter'; + +import { AnalyticsCollectionExploreTable } from './analytics_collection_explore_table'; +import { ExploreTables } from './analytics_collection_explore_table_types'; + +describe('AnalyticsCollectionExploreTable', () => { + const mockValues = { + activeTableId: 'search_terms', + analyticsCollection: { + events_datastream: 'analytics-events-example', + name: 'Analytics-Collection-1', + }, + items: [], + searchFilter: 'searches', + }; + const mockActions = { + findDataView: jest.fn(), + setSelectedTable: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + + setMockValues(mockValues); + setMockActions(mockActions); + }); + + it('should call setSelectedTable with the correct table id when a tab is clicked', () => { + const wrapper = shallow(<AnalyticsCollectionExploreTable filterBy={FilterBy.Sessions} />); + + const topReferrersTab = wrapper.find(EuiTab).at(0); + topReferrersTab.simulate('click'); + + expect(mockActions.setSelectedTable).toHaveBeenCalledTimes(1); + expect(mockActions.setSelectedTable).toHaveBeenCalledWith(ExploreTables.TopReferrers, { + direction: 'desc', + field: 'sessions', + }); + }); + + it('should call findDataView with the active table ID and search filter when mounted', () => { + mount(<AnalyticsCollectionExploreTable filterBy={FilterBy.Sessions} />); + expect(mockActions.findDataView).toHaveBeenCalledWith(mockValues.analyticsCollection); + }); + + it('should render a table with the selectedTable', () => { + setMockValues({ ...mockValues, selectedTable: ExploreTables.WorsePerformers }); + const wrapper = mount(<AnalyticsCollectionExploreTable filterBy={FilterBy.Sessions} />); + expect(wrapper.find(EuiBasicTable).prop('itemId')).toBe(ExploreTables.WorsePerformers); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table.tsx new file mode 100644 index 0000000000000..7b77cdb05cf61 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table.tsx @@ -0,0 +1,321 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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, { useEffect, useMemo } from 'react'; + +import { useActions, useValues } from 'kea'; + +import { + EuiBasicTable, + EuiBasicTableColumn, + EuiButton, + EuiFlexGroup, + EuiTab, + EuiTabs, + EuiText, + useEuiTheme, +} from '@elastic/eui'; + +import { + EuiTableFieldDataColumnType, + EuiTableSortingType, +} from '@elastic/eui/src/components/basic_table/table_types'; +import { UseEuiTheme } from '@elastic/eui/src/services/theme/hooks'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; + +import { generateEncodedPath } from '../../../../shared/encode_path_params'; + +import { KibanaLogic } from '../../../../shared/kibana'; +import { COLLECTION_EXPLORER_PATH } from '../../../routes'; +import { FilterBy } from '../../../utils/get_formula_by_filter'; +import { FetchAnalyticsCollectionLogic } from '../fetch_analytics_collection_logic'; + +import { AnalyticsCollectionExploreTableLogic } from './analytics_collection_explore_table_logic'; +import { + ExploreTableColumns, + ExploreTableItem, + ExploreTables, + SearchTermsTable, + TopClickedTable, + TopReferrersTable, + WorsePerformersTable, +} from './analytics_collection_explore_table_types'; + +const tabsByFilter: Record<FilterBy, Array<{ id: ExploreTables; name: string }>> = { + [FilterBy.Searches]: [ + { + id: ExploreTables.SearchTerms, + name: i18n.translate( + 'xpack.enterpriseSearch.analytics.collections.collectionsView.exploreTab.searchTerms', + { defaultMessage: 'Popular search terms' } + ), + }, + ], + [FilterBy.NoResults]: [ + { + id: ExploreTables.WorsePerformers, + name: i18n.translate( + 'xpack.enterpriseSearch.analytics.collections.collectionsView.exploreTab.worsePerformers', + { defaultMessage: 'Worse performers' } + ), + }, + ], + [FilterBy.Clicks]: [ + { + id: ExploreTables.TopClicked, + name: i18n.translate( + 'xpack.enterpriseSearch.analytics.collections.collectionsView.exploreTab.topClicked', + { defaultMessage: 'Top clicked results' } + ), + }, + ], + [FilterBy.Sessions]: [ + { + id: ExploreTables.TopReferrers, + name: i18n.translate( + 'xpack.enterpriseSearch.analytics.collections.collectionsView.exploreTab.topReferrers', + { defaultMessage: 'Top referrers' } + ), + }, + ], +}; + +interface TableSetting<T = ExploreTableItem, K = T> { + columns: Array< + EuiBasicTableColumn<T & K> & { + render?: (euiTheme: UseEuiTheme['euiTheme']) => EuiTableFieldDataColumnType<T & K>['render']; + } + >; + sorting: EuiTableSortingType<T>; +} + +const tableSettings: { + [ExploreTables.SearchTerms]: TableSetting<SearchTermsTable>; + [ExploreTables.TopClicked]: TableSetting<TopClickedTable>; + [ExploreTables.TopReferrers]: TableSetting<TopReferrersTable>; + [ExploreTables.WorsePerformers]: TableSetting<WorsePerformersTable>; +} = { + [ExploreTables.SearchTerms]: { + columns: [ + { + field: ExploreTableColumns.searchTerms, + name: i18n.translate( + 'xpack.enterpriseSearch.analytics.collections.collectionsView.exploreTable.searchTerms', + { defaultMessage: 'Search Terms' } + ), + truncateText: true, + }, + { + align: 'right', + field: ExploreTableColumns.count, + name: i18n.translate( + 'xpack.enterpriseSearch.analytics.collections.collectionsView.exploreTable.count', + { defaultMessage: 'Count' } + ), + sortable: true, + truncateText: true, + }, + ], + sorting: { + readOnly: true, + sort: { + direction: 'desc', + field: ExploreTableColumns.count, + }, + }, + }, + [ExploreTables.WorsePerformers]: { + columns: [ + { + field: ExploreTableColumns.query, + name: i18n.translate( + 'xpack.enterpriseSearch.analytics.collections.collectionsView.exploreTable.query', + { defaultMessage: 'Query' } + ), + truncateText: true, + }, + { + align: 'right', + field: ExploreTableColumns.count, + name: i18n.translate( + 'xpack.enterpriseSearch.analytics.collections.collectionsView.exploreTable.count', + { defaultMessage: 'Count' } + ), + sortable: true, + truncateText: true, + }, + ], + sorting: { + readOnly: true, + sort: { + direction: 'desc', + field: ExploreTableColumns.count, + }, + }, + }, + [ExploreTables.TopClicked]: { + columns: [ + { + field: ExploreTableColumns.page, + name: i18n.translate( + 'xpack.enterpriseSearch.analytics.collections.collectionsView.exploreTable.page', + { defaultMessage: 'Page' } + ), + render: (euiTheme: UseEuiTheme['euiTheme']) => (value: string) => + ( + <EuiText size="s" color={euiTheme.colors.primaryText}> + <p>{value}</p> + </EuiText> + ), + truncateText: true, + }, + { + align: 'right', + field: ExploreTableColumns.count, + name: i18n.translate( + 'xpack.enterpriseSearch.analytics.collections.collectionsView.exploreTable.count', + { defaultMessage: 'Count' } + ), + sortable: true, + truncateText: true, + }, + ], + sorting: { + readOnly: true, + sort: { + direction: 'desc', + field: ExploreTableColumns.count, + }, + }, + }, + [ExploreTables.TopReferrers]: { + columns: [ + { + field: ExploreTableColumns.page, + name: i18n.translate( + 'xpack.enterpriseSearch.analytics.collections.collectionsView.exploreTable.page', + { defaultMessage: 'Page' } + ), + render: (euiTheme: UseEuiTheme['euiTheme']) => (value: string) => + ( + <EuiText size="s" color={euiTheme.colors.primaryText}> + <p>{value}</p> + </EuiText> + ), + truncateText: true, + }, + { + align: 'right', + field: ExploreTableColumns.sessions, + name: i18n.translate( + 'xpack.enterpriseSearch.analytics.collections.collectionsView.exploreTable.session', + { defaultMessage: 'Session' } + ), + sortable: true, + truncateText: true, + }, + ], + sorting: { + readOnly: true, + sort: { + direction: 'desc', + field: ExploreTableColumns.sessions, + }, + }, + }, +}; + +interface AnalyticsCollectionExploreTableProps { + filterBy: FilterBy; +} + +export const AnalyticsCollectionExploreTable: React.FC<AnalyticsCollectionExploreTableProps> = ({ + filterBy, +}) => { + const { euiTheme } = useEuiTheme(); + const { navigateToUrl } = useValues(KibanaLogic); + const { analyticsCollection } = useValues(FetchAnalyticsCollectionLogic); + const { findDataView, setSelectedTable, setSorting } = useActions( + AnalyticsCollectionExploreTableLogic + ); + const { items, isLoading, selectedTable, sorting } = useValues( + AnalyticsCollectionExploreTableLogic + ); + const tabs = tabsByFilter[filterBy]; + + useEffect(() => { + findDataView(analyticsCollection); + }, [analyticsCollection]); + + useEffect(() => { + const firstTableInTabsId = tabs[0].id; + + setSelectedTable( + firstTableInTabsId, + (tableSettings[firstTableInTabsId] as TableSetting)?.sorting?.sort + ); + }, [tabs]); + + return ( + <EuiFlexGroup direction="column" gutterSize="l"> + <EuiTabs> + {tabs?.map(({ id, name }) => ( + <EuiTab + key={id} + onClick={() => setSelectedTable(id, (tableSettings[id] as TableSetting)?.sorting?.sort)} + isSelected={id === selectedTable} + > + {name} + </EuiTab> + ))} + </EuiTabs> + + {useMemo(() => { + const table = selectedTable !== null && (tableSettings[selectedTable] as TableSetting); + + return ( + table && ( + <EuiBasicTable + columns={ + table.columns.map((column) => ({ + ...column, + render: column.render?.(euiTheme), + })) as TableSetting['columns'] + } + itemId={selectedTable} + items={items} + loading={isLoading} + sorting={table.sorting} + onChange={({ sort }) => { + setSorting(sort); + }} + /> + ) + ); + }, [selectedTable, sorting, items, isLoading])} + + <EuiFlexGroup> + <EuiButton + fill + onClick={() => + navigateToUrl( + generateEncodedPath(COLLECTION_EXPLORER_PATH, { + name: analyticsCollection.name, + }) + ) + } + > + <FormattedMessage + id="xpack.enterpriseSearch.analytics.collections.collectionsView.list.exploreButton" + defaultMessage="Explore all" + /> + </EuiButton> + </EuiFlexGroup> + </EuiFlexGroup> + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table_logic.test.ts new file mode 100644 index 0000000000000..4220c30985a95 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table_logic.test.ts @@ -0,0 +1,149 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { LogicMounter } from '../../../../__mocks__/kea_logic'; + +import { DataView } from '@kbn/data-views-plugin/common'; + +import { AnalyticsCollection } from '../../../../../../common/types/analytics'; + +import { KibanaLogic } from '../../../../shared/kibana/kibana_logic'; + +import { AnalyticsCollectionToolbarLogic } from '../analytics_collection_toolbar/analytics_collection_toolbar_logic'; + +import { + AnalyticsCollectionExploreTableLogic, + Sorting, +} from './analytics_collection_explore_table_logic'; +import { ExploreTableColumns, ExploreTables } from './analytics_collection_explore_table_types'; + +jest.mock('../../../../shared/kibana/kibana_logic', () => ({ + KibanaLogic: { + values: { + data: { + dataViews: { + find: jest.fn(() => Promise.resolve([{ id: 'some-data-view-id' }])), + }, + search: { + search: jest.fn().mockReturnValue({ subscribe: jest.fn() }), + }, + }, + }, + }, +})); + +describe('AnalyticsCollectionExplorerTablesLogic', () => { + const { mount } = new LogicMounter(AnalyticsCollectionExploreTableLogic); + + beforeEach(() => { + jest.clearAllMocks(); + + mount(); + }); + + const defaultProps = { + dataView: null, + isLoading: false, + items: [], + selectedTable: null, + sorting: null, + }; + + it('initializes with default values', () => { + expect(AnalyticsCollectionExploreTableLogic.values).toEqual(defaultProps); + }); + + describe('reducers', () => { + it('should handle set dataView', () => { + const dataView = { id: 'test' } as DataView; + AnalyticsCollectionExploreTableLogic.actions.setDataView(dataView); + expect(AnalyticsCollectionExploreTableLogic.values.dataView).toBe(dataView); + }); + + it('should handle set items', () => { + const items = [ + { count: 1, query: 'test' }, + { count: 2, query: 'test2' }, + ]; + AnalyticsCollectionExploreTableLogic.actions.setItems(items); + expect(AnalyticsCollectionExploreTableLogic.values.items).toEqual(items); + }); + + it('should handle set selectedTable', () => { + const id = ExploreTables.WorsePerformers; + const sorting = { direction: 'desc', field: ExploreTableColumns.count } as Sorting; + AnalyticsCollectionExploreTableLogic.actions.setSelectedTable(id, sorting); + expect(AnalyticsCollectionExploreTableLogic.values.selectedTable).toEqual(id); + expect(AnalyticsCollectionExploreTableLogic.values.sorting).toEqual(sorting); + }); + + it('should handle set sorting', () => { + const sorting = { direction: 'asc', field: ExploreTableColumns.sessions } as Sorting; + AnalyticsCollectionExploreTableLogic.actions.setSorting(sorting); + expect(AnalyticsCollectionExploreTableLogic.values.sorting).toEqual(sorting); + }); + + it('should handle isLoading', () => { + expect(AnalyticsCollectionExploreTableLogic.values.isLoading).toEqual(false); + + AnalyticsCollectionExploreTableLogic.actions.setItems([]); + expect(AnalyticsCollectionExploreTableLogic.values.isLoading).toEqual(false); + + AnalyticsCollectionExploreTableLogic.actions.setSelectedTable(ExploreTables.WorsePerformers); + expect(AnalyticsCollectionExploreTableLogic.values.isLoading).toEqual(true); + + AnalyticsCollectionToolbarLogic.actions.setTimeRange({ from: 'now-7d', to: 'now' }); + expect(AnalyticsCollectionExploreTableLogic.values.isLoading).toEqual(true); + + AnalyticsCollectionToolbarLogic.actions.setSearchSessionId('12345'); + expect(AnalyticsCollectionExploreTableLogic.values.isLoading).toEqual(true); + }); + }); + + describe('listeners', () => { + it('should fetch items when selectedTable changes', () => { + AnalyticsCollectionExploreTableLogic.actions.setSelectedTable(ExploreTables.TopReferrers); + expect(KibanaLogic.values.data.search.search).toHaveBeenCalledWith(expect.any(Object), { + indexPattern: undefined, + sessionId: undefined, + }); + }); + + it('should fetch items when timeRange changes', () => { + AnalyticsCollectionExploreTableLogic.actions.setSelectedTable(ExploreTables.WorsePerformers); + (KibanaLogic.values.data.search.search as jest.Mock).mockClear(); + + AnalyticsCollectionToolbarLogic.actions.setTimeRange({ from: 'now-7d', to: 'now' }); + expect(KibanaLogic.values.data.search.search).toHaveBeenCalledWith(expect.any(Object), { + indexPattern: undefined, + sessionId: undefined, + }); + }); + + it('should fetch items when searchSessionId changes', () => { + AnalyticsCollectionExploreTableLogic.actions.setSelectedTable(ExploreTables.WorsePerformers); + (KibanaLogic.values.data.search.search as jest.Mock).mockClear(); + + AnalyticsCollectionToolbarLogic.actions.setSearchSessionId('1234'); + expect(KibanaLogic.values.data.search.search).toHaveBeenCalledWith(expect.any(Object), { + indexPattern: undefined, + sessionId: '1234', + }); + }); + + it('should find and set dataView when findDataView is called', async () => { + const dataView = { id: 'test' } as DataView; + jest.spyOn(KibanaLogic.values.data.dataViews, 'find').mockResolvedValue([dataView]); + await AnalyticsCollectionExploreTableLogic.actions.findDataView({ + events_datastream: 'events1', + name: 'collection1', + } as AnalyticsCollection); + + expect(AnalyticsCollectionExploreTableLogic.values.dataView).toEqual(dataView); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table_logic.ts new file mode 100644 index 0000000000000..46df5692aa963 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table_logic.ts @@ -0,0 +1,333 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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 { kea, MakeLogicType } from 'kea'; + +import { + IKibanaSearchRequest, + IKibanaSearchResponse, + isCompleteResponse, + TimeRange, +} from '@kbn/data-plugin/common'; +import { DataView } from '@kbn/data-views-plugin/common'; + +import { AnalyticsCollection } from '../../../../../../common/types/analytics'; +import { KibanaLogic } from '../../../../shared/kibana/kibana_logic'; +import { AnalyticsCollectionToolbarLogic } from '../analytics_collection_toolbar/analytics_collection_toolbar_logic'; + +import { + ExploreTableColumns, + ExploreTableItem, + ExploreTables, + SearchTermsTable, + TopClickedTable, + TopReferrersTable, + WorsePerformersTable, +} from './analytics_collection_explore_table_types'; + +const BASE_PAGE_SIZE = 10; + +export interface Sorting<T extends ExploreTableItem = ExploreTableItem> { + direction: 'asc' | 'desc'; + field: keyof T; +} + +interface TableParams<T extends ExploreTableItem = ExploreTableItem> { + parseResponseToItems(response: IKibanaSearchResponse): T[]; + requestParams(timeRange: TimeRange, sorting: Sorting<T> | null): IKibanaSearchRequest; +} + +const tablesParams: { + [ExploreTables.SearchTerms]: TableParams<SearchTermsTable>; + [ExploreTables.TopClicked]: TableParams<TopClickedTable>; + [ExploreTables.TopReferrers]: TableParams<TopReferrersTable>; + [ExploreTables.WorsePerformers]: TableParams<WorsePerformersTable>; +} = { + [ExploreTables.SearchTerms]: { + parseResponseToItems: ( + response: IKibanaSearchResponse<{ + aggregations: { searches: { buckets: Array<{ doc_count: number; key: string }> } }; + }> + ) => + response.rawResponse.aggregations.searches.buckets.map((bucket) => ({ + [ExploreTableColumns.count]: bucket.doc_count, + [ExploreTableColumns.searchTerms]: bucket.key, + })), + requestParams: (timeRange, sorting) => ({ + params: { + aggs: { + searches: { + terms: { + field: 'search.query', + order: sorting + ? { + [sorting.field === ExploreTableColumns.count ? '_count' : '_key']: + sorting.direction, + } + : undefined, + size: BASE_PAGE_SIZE, + }, + }, + }, + query: { + range: { + '@timestamp': { + gte: timeRange.from, + lt: timeRange.to, + }, + }, + }, + size: 0, + track_total_hits: false, + }, + }), + }, + [ExploreTables.WorsePerformers]: { + parseResponseToItems: ( + response: IKibanaSearchResponse<{ + aggregations: { + formula: { searches: { buckets: Array<{ doc_count: number; key: string }> } }; + }; + }> + ) => + response.rawResponse.aggregations.formula.searches.buckets.map((bucket) => ({ + [ExploreTableColumns.count]: bucket.doc_count, + [ExploreTableColumns.query]: bucket.key, + })), + requestParams: (timeRange, sorting) => ({ + params: { + aggs: { + formula: { + aggs: { + searches: { + terms: { + field: 'search.query', + order: sorting + ? { + [sorting?.field === ExploreTableColumns.count ? '_count' : '_key']: + sorting?.direction, + } + : undefined, + size: BASE_PAGE_SIZE, + }, + }, + }, + filter: { term: { 'search.results.total_results': '0' } }, + }, + }, + query: { + range: { + '@timestamp': { + gte: timeRange.from, + lt: timeRange.to, + }, + }, + }, + size: 0, + track_total_hits: false, + }, + }), + }, + [ExploreTables.TopClicked]: { + parseResponseToItems: ( + response: IKibanaSearchResponse<{ + aggregations: { + formula: { searches: { buckets: Array<{ doc_count: number; key: string }> } }; + }; + }> + ) => + response.rawResponse.aggregations.formula.searches.buckets.map((bucket) => ({ + [ExploreTableColumns.count]: bucket.doc_count, + [ExploreTableColumns.page]: bucket.key, + })), + requestParams: (timeRange, sorting) => ({ + params: { + aggs: { + formula: { + aggs: { + searches: { + terms: { + field: 'search.results.items.page.url', + order: sorting + ? { + [sorting.field === ExploreTableColumns.count ? '_count' : '_key']: + sorting.direction, + } + : undefined, + size: BASE_PAGE_SIZE, + }, + }, + }, + filter: { term: { 'event.action': 'search_click' } }, + }, + }, + query: { + range: { + '@timestamp': { + gte: timeRange.from, + lt: timeRange.to, + }, + }, + }, + size: 0, + track_total_hits: false, + }, + }), + }, + [ExploreTables.TopReferrers]: { + parseResponseToItems: ( + response: IKibanaSearchResponse<{ + aggregations: { + formula: { searches: { buckets: Array<{ doc_count: number; key: string }> } }; + }; + }> + ) => + response.rawResponse.aggregations.formula.searches.buckets.map((bucket) => ({ + [ExploreTableColumns.sessions]: bucket.doc_count, + [ExploreTableColumns.page]: bucket.key, + })), + requestParams: (timeRange, sorting) => ({ + params: { + aggs: { + formula: { + aggs: { + searches: { + terms: { + field: 'page.referrer', + order: sorting + ? { + [sorting?.field === ExploreTableColumns.sessions ? '_count' : '_key']: + sorting?.direction, + } + : undefined, + size: BASE_PAGE_SIZE, + }, + }, + }, + filter: { term: { 'event.action': 'page_view' } }, + }, + }, + query: { + range: { + '@timestamp': { + gte: timeRange.from, + lt: timeRange.to, + }, + }, + }, + size: 0, + track_total_hits: false, + }, + }), + }, +}; + +export interface AnalyticsCollectionExploreTableLogicValues { + dataView: DataView | null; + isLoading: boolean; + items: ExploreTableItem[]; + selectedTable: ExploreTables | null; + sorting: Sorting | null; +} + +export interface AnalyticsCollectionExploreTableLogicActions { + findDataView(collection: AnalyticsCollection): { collection: AnalyticsCollection }; + setDataView(dataView: DataView): { dataView: DataView }; + setItems(items: ExploreTableItem[]): { items: ExploreTableItem[] }; + setSelectedTable( + id: ExploreTables | null, + sorting?: Sorting + ): { id: ExploreTables | null; sorting?: Sorting }; + setSorting(sorting?: Sorting): { sorting?: Sorting }; +} + +export const AnalyticsCollectionExploreTableLogic = kea< + MakeLogicType< + AnalyticsCollectionExploreTableLogicValues, + AnalyticsCollectionExploreTableLogicActions + > +>({ + actions: { + findDataView: (collection) => ({ collection }), + setDataView: (dataView) => ({ dataView }), + setItems: (items) => ({ items }), + setSelectedTable: (id, sorting) => ({ id, sorting }), + setSorting: (sorting) => ({ sorting }), + }, + listeners: ({ actions, values }) => { + const fetchItems = () => { + if (values.selectedTable === null || !(values.selectedTable in tablesParams)) { + return; + } + + const { requestParams, parseResponseToItems } = tablesParams[ + values.selectedTable + ] as TableParams; + const timeRange = AnalyticsCollectionToolbarLogic.values.timeRange; + + const search$ = KibanaLogic.values.data.search + .search(requestParams(timeRange, values.sorting), { + indexPattern: values.dataView || undefined, + sessionId: AnalyticsCollectionToolbarLogic.values.searchSessionId, + }) + .subscribe({ + error: (e) => { + KibanaLogic.values.data.search.showError(e); + }, + next: (response) => { + if (isCompleteResponse(response)) { + actions.setItems(parseResponseToItems(response)); + search$.unsubscribe(); + } + }, + }); + }; + + return { + findDataView: async ({ collection }) => { + const dataView = ( + await KibanaLogic.values.data.dataViews.find(collection.events_datastream, 1) + )?.[0]; + + if (dataView) { + actions.setDataView(dataView); + } + }, + setSelectedTable: () => { + fetchItems(); + }, + [AnalyticsCollectionToolbarLogic.actionTypes.setTimeRange]: () => { + fetchItems(); + }, + [AnalyticsCollectionToolbarLogic.actionTypes.setSearchSessionId]: () => { + fetchItems(); + }, + }; + }, + path: ['enterprise_search', 'analytics', 'collections', 'explore', 'table'], + reducers: () => ({ + dataView: [null, { setDataView: (_, { dataView }) => dataView }], + isLoading: [ + false, + { + setItems: () => false, + setSelectedTable: () => true, + [AnalyticsCollectionToolbarLogic.actionTypes.setTimeRange]: () => true, + [AnalyticsCollectionToolbarLogic.actionTypes.setSearchSessionId]: () => true, + }, + ], + items: [[], { setItems: (_, { items }) => items }], + selectedTable: [null, { setSelectedTable: (_, { id }) => id }], + sorting: [ + null, + { + setSelectedTable: (_, { sorting = null }) => sorting, + setSorting: (_, { sorting = null }) => sorting, + }, + ], + }), +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table_types.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table_types.ts new file mode 100644 index 0000000000000..c9c6e4c3a0244 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table/analytics_collection_explore_table_types.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. + */ + +export enum ExploreTables { + SearchTerms, + WorsePerformers, + TopClicked, + TopReferrers, +} + +export enum ExploreTableColumns { + count = 'count', + searchTerms = 'searchTerms', + query = 'query', + page = 'page', + sessions = 'sessions', +} + +export interface SearchTermsTable { + [ExploreTableColumns.count]: number; + [ExploreTableColumns.searchTerms]: string; +} + +export interface WorsePerformersTable { + [ExploreTableColumns.count]: number; + [ExploreTableColumns.query]: string; +} + +export interface TopClickedTable { + [ExploreTableColumns.count]: number; + [ExploreTableColumns.page]: string; +} + +export interface TopReferrersTable { + [ExploreTableColumns.page]: string; + [ExploreTableColumns.sessions]: number; +} + +export type ExploreTableItem = + | SearchTermsTable + | WorsePerformersTable + | TopClickedTable + | TopReferrersTable; diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview.tsx deleted file mode 100644 index e0df130e9256b..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { useActions, useValues } from 'kea'; - -import { i18n } from '@kbn/i18n'; - -import { AnalyticsCollection } from '../../../../../common/types/analytics'; - -import { EnterpriseSearchAnalyticsPageTemplate } from '../layout/page_template'; - -import { AnalyticsCollectionChartWithLens } from './analytics_collection_chart'; -import { AnalyticsCollectionToolbar } from './analytics_collection_toolbar/analytics_collection_toolbar'; -import { AnalyticsCollectionToolbarLogic } from './analytics_collection_toolbar/analytics_collection_toolbar_logic'; - -interface AnalyticsCollectionOverviewProps { - analyticsCollection: AnalyticsCollection; -} - -export const AnalyticsCollectionOverview: React.FC<AnalyticsCollectionOverviewProps> = ({ - analyticsCollection, -}) => { - const { setTimeRange } = useActions(AnalyticsCollectionToolbarLogic); - const { timeRange, searchSessionId } = useValues(AnalyticsCollectionToolbarLogic); - - return ( - <EnterpriseSearchAnalyticsPageTemplate - restrictWidth - pageChrome={[analyticsCollection?.name]} - analyticsName={analyticsCollection?.name} - pageViewTelemetry={`View Analytics Collection - Overview`} - pageHeader={{ - bottomBorder: false, - pageTitle: i18n.translate('xpack.enterpriseSearch.analytics.collectionsView.title', { - defaultMessage: 'Overview', - }), - rightSideItems: [<AnalyticsCollectionToolbar />], - }} - > - <AnalyticsCollectionChartWithLens - id={'analytics-collection-chart-' + analyticsCollection.name} - dataViewQuery={analyticsCollection.events_datastream} - timeRange={timeRange} - setTimeRange={setTimeRange} - searchSessionId={searchSessionId} - /> - </EnterpriseSearchAnalyticsPageTemplate> - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_chart.test.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_chart.test.tsx similarity index 91% rename from x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_chart.test.tsx rename to x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_chart.test.tsx index 80702bdccb4b9..31831805a7f4f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_chart.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_chart.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { setMockValues } from '../../../__mocks__/kea_logic'; +import { setMockValues } from '../../../../__mocks__/kea_logic'; import React from 'react'; @@ -16,7 +16,7 @@ import moment from 'moment'; import { AreaSeries, Chart } from '@elastic/charts'; import { EuiLoadingChart } from '@elastic/eui'; -import { FilterBy } from '../../utils/get_formula_by_filter'; +import { FilterBy } from '../../../utils/get_formula_by_filter'; import { AnalyticsCollectionChart } from './analytics_collection_chart'; @@ -42,6 +42,8 @@ describe('AnalyticsCollectionChart', () => { dataViewQuery: mockedDataViewQuery, id: 'mockedId', isLoading: false, + selectedChart: FilterBy.Searches, + setSelectedChart: jest.fn(), timeRange: mockedTimeRange, }; diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_chart.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_chart.tsx similarity index 59% rename from x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_chart.tsx rename to x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_chart.tsx index 176da2fa8563d..9a86c758bf585 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_chart.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_chart.tsx @@ -33,12 +33,10 @@ import { DateHistogramIndexPatternColumn, TypedLensByValueInput } from '@kbn/len import { euiThemeVars } from '@kbn/ui-theme'; -import { KibanaLogic } from '../../../shared/kibana'; +import { KibanaLogic } from '../../../../shared/kibana'; -import { withLensData, WithLensDataInputProps } from '../../hoc/with_lens_data'; -import { FilterBy as ChartIds, getFormulaByFilter } from '../../utils/get_formula_by_filter'; - -import { AnalyticsCollectionViewMetricWithLens } from './analytics_collection_metric'; +import { withLensData, WithLensDataInputProps } from '../../../hoc/with_lens_data'; +import { FilterBy, getFormulaByFilter } from '../../../utils/get_formula_by_filter'; const DEFAULT_STROKE_WIDTH = 1; const HOVER_STROKE_WIDTH = 3; @@ -46,33 +44,33 @@ const CHART_HEIGHT = 490; interface AnalyticsCollectionChartProps extends WithLensDataInputProps { dataViewQuery: string; + selectedChart: FilterBy | null; + setSelectedChart(chart: FilterBy): void; } interface AnalyticsCollectionChartLensProps { data: { - [key in ChartIds]?: Array<[number, number]>; + [key in FilterBy]?: Array<[number, number]>; }; isLoading: boolean; } export const AnalyticsCollectionChart: React.FC< AnalyticsCollectionChartProps & AnalyticsCollectionChartLensProps -> = ({ id: lensId, data, timeRange, dataViewQuery, isLoading, searchSessionId }) => { +> = ({ data, timeRange, isLoading, selectedChart, setSelectedChart }) => { const [currentData, setCurrentData] = useState(data); - const [hoverChart, setHoverChart] = useState<ChartIds | null>(null); - const [selectedChart, setSelectedChart] = useState<ChartIds>(ChartIds.Searches); + const [hoverChart, setHoverChart] = useState<FilterBy | null>(null); const { uiSettings, charts: chartSettings } = useValues(KibanaLogic); const fromDateParsed = DateMath.parse(timeRange.from); const toDataParsed = DateMath.parse(timeRange.to); const chartTheme = chartSettings.theme.useChartsTheme(); const baseChartTheme = chartSettings.theme.useChartsBaseTheme(); - const charts = useMemo( () => [ { chartColor: euiThemeVars.euiColorVis0, - data: currentData[ChartIds.Searches] || [], - id: ChartIds.Searches, + data: currentData[FilterBy.Searches] || [], + id: FilterBy.Searches, name: i18n.translate( 'xpack.enterpriseSearch.analytics.collections.collectionsView.charts.searches', { @@ -82,8 +80,8 @@ export const AnalyticsCollectionChart: React.FC< }, { chartColor: euiThemeVars.euiColorVis2, - data: currentData[ChartIds.NoResults] || [], - id: ChartIds.NoResults, + data: currentData[FilterBy.NoResults] || [], + id: FilterBy.NoResults, name: i18n.translate( 'xpack.enterpriseSearch.analytics.collections.collectionsView.charts.noResults', { @@ -93,8 +91,8 @@ export const AnalyticsCollectionChart: React.FC< }, { chartColor: euiThemeVars.euiColorVis3, - data: currentData[ChartIds.Clicks] || [], - id: ChartIds.Clicks, + data: currentData[FilterBy.Clicks] || [], + id: FilterBy.Clicks, name: i18n.translate( 'xpack.enterpriseSearch.analytics.collections.collectionsView.charts.clicks', { @@ -104,8 +102,8 @@ export const AnalyticsCollectionChart: React.FC< }, { chartColor: euiThemeVars.euiColorVis5, - data: currentData[ChartIds.Sessions] || [], - id: ChartIds.Sessions, + data: currentData[FilterBy.Sessions] || [], + id: FilterBy.Sessions, name: i18n.translate( 'xpack.enterpriseSearch.analytics.collections.collectionsView.charts.sessions', { @@ -123,111 +121,82 @@ export const AnalyticsCollectionChart: React.FC< } }, [data]); - return ( - <EuiFlexGroup direction="column"> - <EuiFlexGroup gutterSize="m"> - {charts.map(({ name, id }) => ( - <AnalyticsCollectionViewMetricWithLens - key={id} - id={`${lensId}-metric-${id}`} - isSelected={selectedChart === id} - name={name} - onClick={(event) => { - event.currentTarget?.blur(); - - setSelectedChart(id); - }} - searchSessionId={searchSessionId} - timeRange={timeRange} - dataViewQuery={dataViewQuery} - getFormula={getFormulaByFilter.bind(null, id)} - /> - ))} - </EuiFlexGroup> - - {isLoading && Object.keys(currentData).length === 0 ? ( - <EuiFlexGroup alignItems="center" justifyContent="center" css={{ height: CHART_HEIGHT }}> - <EuiLoadingChart size="l" /> - </EuiFlexGroup> - ) : ( - <Chart size={['100%', CHART_HEIGHT]}> - <Settings - theme={chartTheme} - baseTheme={baseChartTheme} - showLegend={false} - onElementClick={(elements) => { - const chartId = (elements as XYChartElementEvent[])[0][1]?.specId; + return isLoading && Object.keys(currentData).length === 0 ? ( + <EuiFlexGroup alignItems="center" justifyContent="center" css={{ height: CHART_HEIGHT }}> + <EuiLoadingChart size="l" /> + </EuiFlexGroup> + ) : ( + <Chart size={['100%', CHART_HEIGHT]}> + <Settings + theme={chartTheme} + baseTheme={baseChartTheme} + showLegend={false} + onElementClick={(elements) => { + const chartId = (elements as XYChartElementEvent[])[0][1]?.specId; - if (chartId) { - setSelectedChart(chartId as ChartIds); - } - }} - onElementOver={(elements) => { - const chartId = (elements as XYChartElementEvent[])[0][1]?.specId; + if (chartId) { + setSelectedChart(chartId as FilterBy); + } + }} + onElementOver={(elements) => { + const chartId = (elements as XYChartElementEvent[])[0][1]?.specId; - if (chartId) { - setHoverChart(chartId as ChartIds); - } - }} - onElementOut={() => setHoverChart(null)} - /> + if (chartId) { + setHoverChart(chartId as FilterBy); + } + }} + onElementOut={() => setHoverChart(null)} + /> - {charts.map(({ data: chartData, id, name, chartColor }) => ( - <AreaSeries - id={id} - key={id} - name={name} - data={chartData} - color={chartColor} - xAccessor={0} - yAccessors={[1]} - areaSeriesStyle={{ - area: { - opacity: 0.2, - visible: selectedChart === id, - }, - line: { - opacity: selectedChart === id ? 1 : 0.5, - strokeWidth: [hoverChart, selectedChart].includes(id) - ? HOVER_STROKE_WIDTH - : DEFAULT_STROKE_WIDTH, - }, - }} - yNice - xScaleType={ScaleType.Time} - yScaleType={ScaleType.Sqrt} - curve={CurveType.CURVE_MONOTONE_X} - /> - ))} + {charts.map(({ data: chartData, id, name, chartColor }) => ( + <AreaSeries + id={id} + key={id} + name={name} + data={chartData} + color={chartColor} + xAccessor={0} + yAccessors={[1]} + areaSeriesStyle={{ + area: { + opacity: 0.2, + visible: selectedChart === id, + }, + line: { + opacity: selectedChart === id ? 1 : 0.5, + strokeWidth: [hoverChart, selectedChart].includes(id) + ? HOVER_STROKE_WIDTH + : DEFAULT_STROKE_WIDTH, + }, + }} + yNice + xScaleType={ScaleType.Time} + yScaleType={ScaleType.Sqrt} + curve={CurveType.CURVE_MONOTONE_X} + /> + ))} - <Axis - id="bottom-axis" - position={Position.Bottom} - tickFormat={ - fromDateParsed && toDataParsed - ? niceTimeFormatter([fromDateParsed.valueOf(), toDataParsed.valueOf()]) - : undefined - } - gridLine={{ visible: true }} - /> + <Axis + id="bottom-axis" + position={Position.Bottom} + tickFormat={ + fromDateParsed && toDataParsed + ? niceTimeFormatter([fromDateParsed.valueOf(), toDataParsed.valueOf()]) + : undefined + } + gridLine={{ visible: true }} + /> - <Axis - gridLine={{ dash: [], visible: true }} - hide - id="left-axis" - position={Position.Left} - /> + <Axis gridLine={{ dash: [], visible: true }} hide id="left-axis" position={Position.Left} /> - <Tooltip - headerFormatter={(tooltipData) => - moment(tooltipData.value).format(uiSettings.get('dateFormat')) - } - maxTooltipItems={1} - type={TooltipType.VerticalCursor} - /> - </Chart> - )} - </EuiFlexGroup> + <Tooltip + headerFormatter={(tooltipData) => + moment(tooltipData.value).format(uiSettings.get('dateFormat')) + } + maxTooltipItems={1} + type={TooltipType.VerticalCursor} + /> + </Chart> ); }; @@ -235,8 +204,8 @@ const initialValues: AnalyticsCollectionChartLensProps = { data: {}, isLoading: true, }; -const LENS_LAYERS: Array<{ formula: string; id: ChartIds; x: string; y: string }> = Object.values( - ChartIds +const LENS_LAYERS: Array<{ formula: string; id: FilterBy; x: string; y: string }> = Object.values( + FilterBy ).map((id) => ({ formula: getFormulaByFilter(id), id, x: 'timeline', y: 'values' })); export const AnalyticsCollectionChartWithLens = withLensData< diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_metric.test.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_metric.test.tsx similarity index 100% rename from x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_metric.test.tsx rename to x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_metric.test.tsx diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_metric.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_metric.tsx similarity index 99% rename from x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_metric.tsx rename to x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_metric.tsx index 3d0ff9d25657f..7660c9e92fa47 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_metric.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_metric.tsx @@ -24,7 +24,7 @@ import { EuiThemeComputed } from '@elastic/eui/src/services/theme/types'; import { i18n } from '@kbn/i18n'; import { euiThemeVars } from '@kbn/ui-theme'; -import { withLensData } from '../../hoc/with_lens_data'; +import { withLensData } from '../../../hoc/with_lens_data'; enum MetricStatus { INCREASE = 'increase', diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_overview.test.tsx similarity index 63% rename from x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview.test.tsx rename to x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_overview.test.tsx index 3de4065975705..65c3b2c845d24 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_overview.test.tsx @@ -5,20 +5,22 @@ * 2.0. */ -import '../../../__mocks__/shallow_useeffect.mock'; +import '../../../../__mocks__/shallow_useeffect.mock'; -import { setMockValues, setMockActions } from '../../../__mocks__/kea_logic'; -import { mockUseParams } from '../../../__mocks__/react_router'; +import { setMockValues, setMockActions } from '../../../../__mocks__/kea_logic'; import React from 'react'; import { shallow } from 'enzyme'; -import { AnalyticsCollection } from '../../../../../common/types/analytics'; -import { EnterpriseSearchAnalyticsPageTemplate } from '../layout/page_template'; +import { AnalyticsCollection } from '../../../../../../common/types/analytics'; +import { FilterBy } from '../../../utils/get_formula_by_filter'; + +import { EnterpriseSearchAnalyticsPageTemplate } from '../../layout/page_template'; import { AnalyticsCollectionChartWithLens } from './analytics_collection_chart'; +import { AnalyticsCollectionViewMetricWithLens } from './analytics_collection_metric'; import { AnalyticsCollectionOverview } from './analytics_collection_overview'; const mockValues = { @@ -42,8 +44,6 @@ const mockActions = { describe('AnalyticsOverView', () => { beforeEach(() => { jest.clearAllMocks(); - - mockUseParams.mockReturnValue({ name: '1', section: 'settings' }); }); it('renders with Data', async () => { @@ -89,6 +89,8 @@ describe('AnalyticsOverView', () => { dataViewQuery: 'analytics-events-example', id: 'analytics-collection-chart-Analytics-Collection-1', searchSessionId: 'session-id', + selectedChart: 'Searches', + setSelectedChart: expect.any(Function), setTimeRange: mockActions.setTimeRange, timeRange: { from: 'now-90d', @@ -96,4 +98,27 @@ describe('AnalyticsOverView', () => { }, }); }); + + it('displays all filter options', () => { + const wrapper = shallow( + <AnalyticsCollectionOverview analyticsCollection={mockValues.analyticsCollection} /> + ); + const filterOptions = wrapper.find(AnalyticsCollectionViewMetricWithLens); + expect(filterOptions).toHaveLength(4); + expect(filterOptions.at(0).props().name).toEqual('Searches'); + expect(filterOptions.at(1).props().name).toEqual('No results'); + expect(filterOptions.at(2).props().name).toEqual('Click'); + expect(filterOptions.at(3).props().name).toEqual('Sessions'); + }); + + it('updates the selected chart when a filter option is clicked', () => { + const wrapper = shallow( + <AnalyticsCollectionOverview analyticsCollection={mockValues.analyticsCollection} /> + ); + const filterOption = wrapper.find(AnalyticsCollectionViewMetricWithLens).at(1); + filterOption.simulate('click', {}); + expect(wrapper.find(AnalyticsCollectionChartWithLens).props().selectedChart).toEqual( + FilterBy.NoResults + ); + }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_overview.tsx new file mode 100644 index 0000000000000..a13d66053ea63 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_overview/analytics_collection_overview.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState } from 'react'; + +import { useActions, useValues } from 'kea'; + +import { EuiFlexGroup } from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + +import { AnalyticsCollection } from '../../../../../../common/types/analytics'; +import { FilterBy, getFormulaByFilter } from '../../../utils/get_formula_by_filter'; + +import { EnterpriseSearchAnalyticsPageTemplate } from '../../layout/page_template'; + +import { AnalyticsCollectionExploreTable } from '../analytics_collection_explore_table/analytics_collection_explore_table'; + +import { AnalyticsCollectionToolbar } from '../analytics_collection_toolbar/analytics_collection_toolbar'; +import { AnalyticsCollectionToolbarLogic } from '../analytics_collection_toolbar/analytics_collection_toolbar_logic'; + +import { AnalyticsCollectionChartWithLens } from './analytics_collection_chart'; +import { AnalyticsCollectionViewMetricWithLens } from './analytics_collection_metric'; + +const filters = [ + { + id: FilterBy.Searches, + name: i18n.translate( + 'xpack.enterpriseSearch.analytics.collections.collectionsView.charts.searches', + { + defaultMessage: 'Searches', + } + ), + }, + { + id: FilterBy.NoResults, + name: i18n.translate( + 'xpack.enterpriseSearch.analytics.collections.collectionsView.charts.noResults', + { + defaultMessage: 'No results', + } + ), + }, + { + id: FilterBy.Clicks, + name: i18n.translate( + 'xpack.enterpriseSearch.analytics.collections.collectionsView.charts.clicks', + { + defaultMessage: 'Click', + } + ), + }, + { + id: FilterBy.Sessions, + name: i18n.translate( + 'xpack.enterpriseSearch.analytics.collections.collectionsView.charts.sessions', + { + defaultMessage: 'Sessions', + } + ), + }, +]; + +interface AnalyticsCollectionOverviewProps { + analyticsCollection: AnalyticsCollection; +} + +export const AnalyticsCollectionOverview: React.FC<AnalyticsCollectionOverviewProps> = ({ + analyticsCollection, +}) => { + const { setTimeRange } = useActions(AnalyticsCollectionToolbarLogic); + const { timeRange, searchSessionId } = useValues(AnalyticsCollectionToolbarLogic); + const [filterBy, setFilterBy] = useState<FilterBy>(FilterBy.Searches); + + return ( + <EnterpriseSearchAnalyticsPageTemplate + restrictWidth + pageChrome={[analyticsCollection?.name]} + analyticsName={analyticsCollection?.name} + pageViewTelemetry={`View Analytics Collection - Overview`} + pageHeader={{ + bottomBorder: false, + pageTitle: i18n.translate('xpack.enterpriseSearch.analytics.collectionsView.title', { + defaultMessage: 'Overview', + }), + rightSideItems: [<AnalyticsCollectionToolbar />], + }} + > + <EuiFlexGroup direction="column"> + <EuiFlexGroup gutterSize="m"> + {filters.map(({ name, id }) => ( + <AnalyticsCollectionViewMetricWithLens + key={id} + id={`analytics-collection-metric-${analyticsCollection.name}-${id}`} + isSelected={filterBy === id} + name={name} + onClick={(event) => { + event.currentTarget?.blur(); + + setFilterBy(id); + }} + dataViewQuery={analyticsCollection.events_datastream} + timeRange={timeRange} + searchSessionId={searchSessionId} + getFormula={getFormulaByFilter.bind(null, id)} + /> + ))} + </EuiFlexGroup> + + <AnalyticsCollectionChartWithLens + id={'analytics-collection-chart-' + analyticsCollection.name} + dataViewQuery={analyticsCollection.events_datastream} + timeRange={timeRange} + setTimeRange={setTimeRange} + searchSessionId={searchSessionId} + selectedChart={filterBy} + setSelectedChart={setFilterBy} + /> + + <AnalyticsCollectionExploreTable filterBy={filterBy} /> + </EuiFlexGroup> + </EnterpriseSearchAnalyticsPageTemplate> + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_view.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_view.tsx index b33f509fb5db7..0db1d77ba6b49 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_view.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_view.tsx @@ -9,9 +9,10 @@ import React, { useEffect } from 'react'; import { useParams } from 'react-router-dom'; import { Switch } from 'react-router-dom'; -import { useActions, useValues } from 'kea'; +import { useActions, useMountedLogic, useValues } from 'kea'; import { EuiEmptyPrompt } from '@elastic/eui'; + import { i18n } from '@kbn/i18n'; import { Route } from '@kbn/shared-ux-router'; @@ -25,11 +26,13 @@ import { AddAnalyticsCollection } from '../add_analytics_collections/add_analyti import { EnterpriseSearchAnalyticsPageTemplate } from '../layout/page_template'; import { AnalyticsCollectionIntegrateView } from './analytics_collection_integrate/analytics_collection_integrate_view'; -import { AnalyticsCollectionOverview } from './analytics_collection_overview'; +import { AnalyticsCollectionOverview } from './analytics_collection_overview/analytics_collection_overview'; +import { AnalyticsCollectionToolbarLogic } from './analytics_collection_toolbar/analytics_collection_toolbar_logic'; import { FetchAnalyticsCollectionLogic } from './fetch_analytics_collection_logic'; export const AnalyticsCollectionView: React.FC = () => { + useMountedLogic(AnalyticsCollectionToolbarLogic); const { fetchAnalyticsCollection } = useActions(FetchAnalyticsCollectionLogic); const { analyticsCollection, isLoading } = useValues(FetchAnalyticsCollectionLogic); const { name } = useParams<{ name: string }>(); From 57d6f413a10fc0fffd0f7062016b1d1b21e37a17 Mon Sep 17 00:00:00 2001 From: Joseph McElroy <joseph.mcelroy@elastic.co> Date: Wed, 12 Apr 2023 12:02:48 +0100 Subject: [PATCH 23/23] [Behavioral Analytics] Add api key modal in integration page (#154738) Add API Key modal to integration page. <img width="812" alt="Screenshot 2023-04-11 at 16 13 40" src="https://user-images.githubusercontent.com/49480/231208531-920272be-bd48-4bb0-971d-c740a2e8b2e2.png"> <img width="882" alt="Screenshot 2023-04-11 at 16 13 46" src="https://user-images.githubusercontent.com/49480/231208527-d8fb2a41-ad9c-4fd3-b7c9-a1cd1de7fe02.png"> <img width="820" alt="Screenshot 2023-04-11 at 16 13 53" src="https://user-images.githubusercontent.com/49480/231208520-e9ec8ae3-e3a7-4dc3-8e6b-f6f339e9f084.png"> <img width="991" alt="Screenshot 2023-04-11 at 16 13 59" src="https://user-images.githubusercontent.com/49480/231208512-791f6a8c-e8ad-4960-840c-8a2bea5ab556.png"> --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../generate_analytics_api_key_logic.test.ts | 54 +++++ .../generate_analytics_api_key_logic.ts | 39 ++++ .../analytics_collection_integrate.test.tsx | 1 + .../analytics_collection_integrate_view.tsx | 120 ++++++++++- ...rate_analytics_api_key_modal.logic.test.ts | 144 +++++++++++++ .../generate_analytics_api_key_modal.logic.ts | 50 +++++ .../generate_analytics_api_key_modal.test.tsx | 94 +++++++++ .../generate_analytics_api_key_modal.tsx | 196 ++++++++++++++++++ .../lib/analytics/create_api_key.test.ts | 46 ++++ .../server/lib/analytics/create_api_key.ts | 19 ++ .../routes/enterprise_search/analytics.ts | 27 +++ 11 files changed, 783 insertions(+), 7 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/public/applications/analytics/api/generate_analytics_api_key/generate_analytics_api_key_logic.test.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/analytics/api/generate_analytics_api_key/generate_analytics_api_key_logic.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/api_key_modal/generate_analytics_api_key_modal.logic.test.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/api_key_modal/generate_analytics_api_key_modal.logic.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/api_key_modal/generate_analytics_api_key_modal.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/api_key_modal/generate_analytics_api_key_modal.tsx create mode 100644 x-pack/plugins/enterprise_search/server/lib/analytics/create_api_key.test.ts create mode 100644 x-pack/plugins/enterprise_search/server/lib/analytics/create_api_key.ts diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/api/generate_analytics_api_key/generate_analytics_api_key_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/api/generate_analytics_api_key/generate_analytics_api_key_logic.test.ts new file mode 100644 index 0000000000000..c1a5950e03073 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/api/generate_analytics_api_key/generate_analytics_api_key_logic.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { mockHttpValues } from '../../../__mocks__/kea_logic'; + +import { nextTick } from '@kbn/test-jest-helpers'; + +import { generateAnalyticsApiKey } from './generate_analytics_api_key_logic'; + +describe('GenerateAnalyticsApiKeyLogic', () => { + const { http } = mockHttpValues; + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('GenerateAnalyticsApiKeyLogic', () => { + it('calls correct api', async () => { + const promise = Promise.resolve({ + apiKey: { + api_key: 'api_key', + encoded: 'encoded', + id: 'id', + name: 'name', + }, + }); + http.post.mockReturnValue(promise); + const result = generateAnalyticsApiKey({ + collectionName: 'puggles', + keyName: 'puggles read only key', + }); + await nextTick(); + expect(http.post).toHaveBeenCalledWith( + '/internal/enterprise_search/analytics/collections/puggles/api_key', + { + body: JSON.stringify({ + keyName: 'puggles read only key', + }), + } + ); + await expect(result).resolves.toEqual({ + apiKey: { + api_key: 'api_key', + encoded: 'encoded', + id: 'id', + name: 'name', + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/api/generate_analytics_api_key/generate_analytics_api_key_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/api/generate_analytics_api_key/generate_analytics_api_key_logic.ts new file mode 100644 index 0000000000000..2603ee977a6a0 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/api/generate_analytics_api_key/generate_analytics_api_key_logic.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createApiLogic } from '../../../shared/api_logic/create_api_logic'; +import { HttpLogic } from '../../../shared/http'; + +interface APIKeyResponse { + apiKey: { + api_key: string; + encoded: string; + id: string; + name: string; + }; +} + +export const generateAnalyticsApiKey = async ({ + collectionName, + keyName, +}: { + collectionName: string; + keyName: string; +}) => { + const route = `/internal/enterprise_search/analytics/collections/${collectionName}/api_key`; + + return await HttpLogic.values.http.post<APIKeyResponse>(route, { + body: JSON.stringify({ + keyName, + }), + }); +}; + +export const generateAnalyticsApiKeyLogic = createApiLogic( + ['generate_analytics_api_key_logic'], + generateAnalyticsApiKey +); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/analytics_collection_integrate.test.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/analytics_collection_integrate.test.tsx index 668f58534ea5e..f1c66a8cedbb6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/analytics_collection_integrate.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/analytics_collection_integrate.test.tsx @@ -6,6 +6,7 @@ */ import '../../../../__mocks__/shallow_useeffect.mock'; +import '../../../../__mocks__/kea_logic'; import React from 'react'; diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/analytics_collection_integrate_view.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/analytics_collection_integrate_view.tsx index 497317712646c..550a16e7a78cc 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/analytics_collection_integrate_view.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/analytics_collection_integrate_view.tsx @@ -5,23 +5,39 @@ * 2.0. */ -import React from 'react'; - -import { EuiSpacer, EuiSteps, EuiTab, EuiTabs } from '@elastic/eui'; +import React, { useState } from 'react'; + +import { useValues } from 'kea'; + +import { + EuiButton, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiSteps, + EuiTab, + EuiTabs, + EuiLink, + EuiText, +} from '@elastic/eui'; import { EuiContainedStepProps } from '@elastic/eui/src/components/steps/steps'; import { i18n } from '@kbn/i18n'; import { AnalyticsCollection } from '../../../../../../common/types/analytics'; +import { docLinks } from '../../../../shared/doc_links'; import { getEnterpriseSearchUrl } from '../../../../shared/enterprise_search_url'; +import { KibanaLogic } from '../../../../shared/kibana'; import { EnterpriseSearchAnalyticsPageTemplate } from '../../layout/page_template'; import { javascriptClientEmbedSteps } from './analytics_collection_integrate_javascript_client_embed'; import { javascriptEmbedSteps } from './analytics_collection_integrate_javascript_embed'; import { searchUIEmbedSteps } from './analytics_collection_integrate_searchui'; +import { GenerateAnalyticsApiKeyModal } from './api_key_modal/generate_analytics_api_key_modal'; +import { GenerateApiKeyModalLogic } from './api_key_modal/generate_analytics_api_key_modal.logic'; interface AnalyticsCollectionIntegrateProps { analyticsCollection: AnalyticsCollection; @@ -35,13 +51,93 @@ export interface AnalyticsConfig { endpoint: string; } +const apiKeyStep = ( + openApiKeyModal: () => void, + navigateToUrl: typeof KibanaLogic.values.navigateToUrl +): EuiContainedStepProps => ({ + title: i18n.translate( + 'xpack.enterpriseSearch.analytics.collections.collectionsView.apiKey.title', + { + defaultMessage: 'Create an API Key', + } + ), + children: ( + <> + <EuiText> + <p> + {i18n.translate( + 'xpack.enterpriseSearch.analytics.collectionsView.integration.apiKeyStep.apiKeyWarning', + { + defaultMessage: + "Elastic does not store API keys. Once generated, you'll only be able to view the key one time. Make sure you save it somewhere secure. If you lose access to it you'll need to generate a new API key from this screen.", + } + )}{' '} + <EuiLink + href={docLinks.apiKeys} + data-telemetry-id="entSearchContent-analytics-apiKey-learnMoreLink" + external + target="_blank" + > + {i18n.translate( + 'xpack.enterpriseSearch.analytics.collectionsView.integration.apiKeyStep.learnMoreLink', + { + defaultMessage: 'Learn more about API keys.', + } + )} + </EuiLink> + </p> + </EuiText> + <EuiSpacer size="l" /> + <EuiFlexGroup gutterSize="s"> + <EuiFlexItem grow={false}> + <EuiButton + iconSide="left" + iconType="plusInCircleFilled" + onClick={openApiKeyModal} + data-telemetry-id="entSearchContent-analytics-apiKey-createApiKeyButton" + > + {i18n.translate( + 'xpack.enterpriseSearch.analytics.collectionsView.integration.apiKeyStep.createAPIKeyButton', + { + defaultMessage: 'Create API Key', + } + )} + </EuiButton> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiButton + iconSide="left" + iconType="popout" + data-telemetry-id="entSearchContent-analytics-apiKey-viewKeysButton" + onClick={() => + navigateToUrl('/app/management/security/api_keys', { + shouldNotCreateHref: true, + }) + } + > + {i18n.translate( + 'xpack.enterpriseSearch.analytics.collectionsView.integration.apiKeyStep.viewKeysButton', + { + defaultMessage: 'View Keys', + } + )} + </EuiButton> + </EuiFlexItem> + </EuiFlexGroup> + </> + ), +}); + export const AnalyticsCollectionIntegrateView: React.FC<AnalyticsCollectionIntegrateProps> = ({ analyticsCollection, }) => { - const [selectedTab, setSelectedTab] = React.useState<TabKey>('javascriptEmbed'); + const [selectedTab, setSelectedTab] = useState<TabKey>('javascriptEmbed'); + const [apiKeyModelOpen, setApiKeyModalOpen] = useState<boolean>(false); + const { navigateToUrl } = useValues(KibanaLogic); + const { apiKey } = useValues(GenerateApiKeyModalLogic); const analyticsConfig: AnalyticsConfig = { - apiKey: '########', + apiKey: apiKey || '########', collectionName: analyticsCollection?.name, endpoint: getEnterpriseSearchUrl(), }; @@ -80,9 +176,11 @@ export const AnalyticsCollectionIntegrateView: React.FC<AnalyticsCollectionInteg }, ]; + const apiKeyStepGuide = apiKeyStep(() => setApiKeyModalOpen(true), navigateToUrl); + const steps: Record<TabKey, EuiContainedStepProps[]> = { - javascriptClientEmbed: javascriptClientEmbedSteps(analyticsConfig), - javascriptEmbed: javascriptEmbedSteps(webClientSrc, analyticsConfig), + javascriptClientEmbed: [apiKeyStepGuide, ...javascriptClientEmbedSteps(analyticsConfig)], + javascriptEmbed: [apiKeyStepGuide, ...javascriptEmbedSteps(webClientSrc, analyticsConfig)], searchuiEmbed: searchUIEmbedSteps(setSelectedTab), }; @@ -111,6 +209,14 @@ export const AnalyticsCollectionIntegrateView: React.FC<AnalyticsCollectionInteg }} > <> + {apiKeyModelOpen ? ( + <GenerateAnalyticsApiKeyModal + collectionName={analyticsCollection.name} + onClose={() => { + setApiKeyModalOpen(false); + }} + /> + ) : null} <EuiTabs> {tabs.map((tab) => ( <EuiTab diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/api_key_modal/generate_analytics_api_key_modal.logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/api_key_modal/generate_analytics_api_key_modal.logic.test.ts new file mode 100644 index 0000000000000..0c5a97588a9e1 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/api_key_modal/generate_analytics_api_key_modal.logic.test.ts @@ -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 { LogicMounter } from '../../../../../__mocks__/kea_logic'; + +import { Status } from '../../../../../../../common/types/api'; + +import { generateAnalyticsApiKeyLogic } from '../../../../api/generate_analytics_api_key/generate_analytics_api_key_logic'; + +import { GenerateApiKeyModalLogic } from './generate_analytics_api_key_modal.logic'; + +const DEFAULT_VALUES = { + apiKey: '', + data: undefined, + isLoading: false, + isSuccess: false, + keyName: '', + status: Status.IDLE, +}; + +describe('GenerateAnalyticsApiKeyModal Logic', () => { + const { mount: apiLogicMount } = new LogicMounter(GenerateApiKeyModalLogic); + const { mount } = new LogicMounter(GenerateApiKeyModalLogic); + + beforeEach(() => { + jest.clearAllMocks(); + apiLogicMount(); + mount(); + }); + + it('has expected default values', () => { + expect(GenerateApiKeyModalLogic.values).toEqual(DEFAULT_VALUES); + }); + + describe('actions', () => { + describe('setKeyName', () => { + it('sets keyName value to the reducer', () => { + const keyName = 'test-key-name 8888*^7896&*^*&'; + expect(GenerateApiKeyModalLogic.values).toEqual(DEFAULT_VALUES); + GenerateApiKeyModalLogic.actions.setKeyName(keyName); + expect(GenerateApiKeyModalLogic.values).toEqual({ + ...DEFAULT_VALUES, + keyName, + }); + }); + }); + }); + + describe('reducers', () => { + describe('keyName', () => { + it('updates when setKeyName action is triggered', () => { + const keyName = 'test-key-name'; + expect(GenerateApiKeyModalLogic.values).toEqual(DEFAULT_VALUES); + GenerateApiKeyModalLogic.actions.setKeyName(keyName); + expect(GenerateApiKeyModalLogic.values).toEqual({ + ...DEFAULT_VALUES, + keyName, + }); + }); + }); + }); + + describe('selectors', () => { + describe('apiKey', () => { + it('updates when apiSuccess listener triggered', () => { + expect(GenerateApiKeyModalLogic.values).toEqual(DEFAULT_VALUES); + generateAnalyticsApiKeyLogic.actions.apiSuccess({ + apiKey: { + api_key: 'some-api-key-123123', + encoded: 'encoded-api-key123123==', + id: 'api_key_id', + name: 'test-key-123', + }, + }); + + expect(GenerateApiKeyModalLogic.values).toEqual({ + apiKey: 'encoded-api-key123123==', + data: { + apiKey: { + api_key: 'some-api-key-123123', + encoded: 'encoded-api-key123123==', + id: 'api_key_id', + name: 'test-key-123', + }, + }, + isLoading: false, + isSuccess: true, + keyName: '', + status: Status.SUCCESS, + }); + }); + }); + + describe('isLoading', () => { + it('should update with API status', () => { + expect(GenerateApiKeyModalLogic.values).toEqual(DEFAULT_VALUES); + generateAnalyticsApiKeyLogic.actions.makeRequest({ + collectionName: 'puggles', + keyName: 'test', + }); + + expect(GenerateApiKeyModalLogic.values).toEqual({ + ...DEFAULT_VALUES, + isLoading: true, + status: Status.LOADING, + }); + }); + }); + + describe('isSuccess', () => { + it('should update with API status', () => { + expect(GenerateApiKeyModalLogic.values).toEqual(DEFAULT_VALUES); + generateAnalyticsApiKeyLogic.actions.apiSuccess({ + apiKey: { + api_key: 'some-api-key-123123', + encoded: 'encoded-api-key123123==', + id: 'api_key_id', + name: 'test-key-123', + }, + }); + + expect(GenerateApiKeyModalLogic.values).toEqual({ + apiKey: 'encoded-api-key123123==', + data: { + apiKey: { + api_key: 'some-api-key-123123', + encoded: 'encoded-api-key123123==', + id: 'api_key_id', + name: 'test-key-123', + }, + }, + isLoading: false, + isSuccess: true, + keyName: '', + status: Status.SUCCESS, + }); + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/api_key_modal/generate_analytics_api_key_modal.logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/api_key_modal/generate_analytics_api_key_modal.logic.ts new file mode 100644 index 0000000000000..9c562e7c4fa14 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/api_key_modal/generate_analytics_api_key_modal.logic.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { kea, MakeLogicType } from 'kea'; + +import { Status } from '../../../../../../../common/types/api'; + +import { generateAnalyticsApiKeyLogic } from '../../../../api/generate_analytics_api_key/generate_analytics_api_key_logic'; + +interface GenerateApiKeyModalActions { + setKeyName(keyName: string): { keyName: string }; +} + +interface GenerateApiKeyModalValues { + apiKey: string; + data: typeof generateAnalyticsApiKeyLogic.values.data; + isLoading: boolean; + isSuccess: boolean; + keyName: string; + status: typeof generateAnalyticsApiKeyLogic.values.status; +} + +export const GenerateApiKeyModalLogic = kea< + MakeLogicType<GenerateApiKeyModalValues, GenerateApiKeyModalActions> +>({ + actions: { + setKeyName: (keyName) => ({ keyName }), + }, + connect: { + values: [generateAnalyticsApiKeyLogic, ['data', 'status']], + }, + path: ['enterprise_search', 'analytics', 'integration', 'generate_api_key_modal'], + reducers: () => ({ + keyName: [ + '', + { + setKeyName: (_, { keyName }) => keyName, + }, + ], + }), + selectors: ({ selectors }) => ({ + apiKey: [() => [selectors.data], (data) => data?.apiKey?.encoded || ''], + isLoading: [() => [selectors.status], (status) => status === Status.LOADING], + isSuccess: [() => [selectors.status], (status) => status === Status.SUCCESS], + }), +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/api_key_modal/generate_analytics_api_key_modal.test.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/api_key_modal/generate_analytics_api_key_modal.test.tsx new file mode 100644 index 0000000000000..2dc27c7f7bfad --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/api_key_modal/generate_analytics_api_key_modal.test.tsx @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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 { setMockValues, setMockActions } from '../../../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow, mount } from 'enzyme'; + +import { EuiModal, EuiFieldText, EuiCodeBlock } from '@elastic/eui'; + +const mockActions = { makeRequest: jest.fn(), setKeyName: jest.fn() }; + +const mockValues = { apiKey: '', isLoading: false, isSuccess: false, keyName: '' }; + +import { GenerateAnalyticsApiKeyModal } from './generate_analytics_api_key_modal'; + +const onCloseMock = jest.fn(); +describe('GenerateAnalyticsApiKeyModal', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(mockValues); + setMockActions(mockActions); + }); + + it('renders the empty modal', () => { + const wrapper = shallow( + <GenerateAnalyticsApiKeyModal collectionName="puggles" onClose={onCloseMock} /> + ); + expect(wrapper.find(EuiModal)).toHaveLength(1); + + wrapper.find(EuiModal).prop('onClose')(); + expect(onCloseMock).toHaveBeenCalled(); + }); + + describe('Modal content', () => { + it('renders API key name form', () => { + const wrapper = shallow( + <GenerateAnalyticsApiKeyModal collectionName="puggles" onClose={onCloseMock} /> + ); + expect(wrapper.find(EuiFieldText)).toHaveLength(1); + expect(wrapper.find('[data-test-subj="generateApiKeyButton"]')).toHaveLength(1); + }); + + it('pre-set the key name with collection name', () => { + mount(<GenerateAnalyticsApiKeyModal collectionName="puggles" onClose={onCloseMock} />); + expect(mockActions.setKeyName).toHaveBeenCalledWith('puggles API key'); + }); + + it('sets keyName name on form', () => { + const wrapper = shallow( + <GenerateAnalyticsApiKeyModal collectionName="puggles" onClose={onCloseMock} /> + ); + const textField = wrapper.find(EuiFieldText); + expect(textField).toHaveLength(1); + textField.simulate('change', { currentTarget: { value: 'changeEvent-key-name' } }); + expect(mockActions.setKeyName).toHaveBeenCalledWith('changeEvent-key-name'); + }); + + it('should trigger api call from the form', () => { + setMockValues({ ...mockValues, collectionName: 'test-123', keyName: ' with-spaces ' }); + const wrapper = shallow( + <GenerateAnalyticsApiKeyModal collectionName="puggles" onClose={onCloseMock} /> + ); + expect(wrapper.find(EuiFieldText)).toHaveLength(1); + wrapper.find('[data-test-subj="generateApiKeyButton"]').simulate('click'); + + expect(mockActions.makeRequest).toHaveBeenCalledWith({ + collectionName: 'puggles', + keyName: 'with-spaces', + }); + }); + it('renders created API key results', () => { + setMockValues({ + ...mockValues, + apiKey: 'apiKeyFromBackend123123==', + collectionName: 'test-123', + isSuccess: true, + keyName: 'keyname', + }); + const wrapper = shallow( + <GenerateAnalyticsApiKeyModal collectionName="puggles" onClose={onCloseMock} /> + ); + expect(wrapper.find(EuiFieldText)).toHaveLength(0); + expect(wrapper.find('[data-test-subj="generateApiKeyButton"]')).toHaveLength(0); + expect(wrapper.find(EuiCodeBlock)).toHaveLength(1); + expect(wrapper.find(EuiCodeBlock).children().text()).toEqual('apiKeyFromBackend123123=='); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/api_key_modal/generate_analytics_api_key_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/api_key_modal/generate_analytics_api_key_modal.tsx new file mode 100644 index 0000000000000..7cf5b76490c4f --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_integrate/api_key_modal/generate_analytics_api_key_modal.tsx @@ -0,0 +1,196 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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, { useEffect } from 'react'; + +import { useValues, useActions } from 'kea'; + +import { + EuiModal, + EuiModalHeader, + EuiModalHeaderTitle, + EuiModalBody, + EuiModalFooter, + EuiFlexGroup, + EuiFlexItem, + EuiPanel, + EuiButton, + EuiButtonEmpty, + EuiButtonIcon, + EuiFieldText, + EuiFormRow, + EuiText, + EuiSpacer, + EuiFormLabel, + EuiCodeBlock, +} from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + +import { generateAnalyticsApiKeyLogic } from '../../../../api/generate_analytics_api_key/generate_analytics_api_key_logic'; + +import { GenerateApiKeyModalLogic } from './generate_analytics_api_key_modal.logic'; + +interface GenerateAnalyticsApiKeyModalProps { + collectionName: string; + onClose(): void; +} + +export const GenerateAnalyticsApiKeyModal: React.FC<GenerateAnalyticsApiKeyModalProps> = ({ + collectionName, + onClose, +}) => { + const { keyName, apiKey, isLoading, isSuccess } = useValues(GenerateApiKeyModalLogic); + const { setKeyName } = useActions(GenerateApiKeyModalLogic); + const { makeRequest } = useActions(generateAnalyticsApiKeyLogic); + + useEffect(() => { + setKeyName(`${collectionName} API key`); + }, [collectionName]); + + return ( + <EuiModal onClose={onClose}> + <EuiModalHeader> + <EuiModalHeaderTitle> + {i18n.translate( + 'xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.title', + { + defaultMessage: 'Create analytics API Key', + } + )} + </EuiModalHeaderTitle> + </EuiModalHeader> + <EuiModalBody> + <> + <EuiPanel hasShadow={false} color="primary"> + <EuiFlexGroup direction="column"> + <EuiFlexItem> + <EuiFlexGroup direction="row" alignItems="flexEnd"> + {!isSuccess ? ( + <> + <EuiFlexItem> + <EuiFormRow label="Name your API key" fullWidth> + <EuiFieldText + data-telemetry-id="entSearchContent-analyticss-api-generateAnalyticsApiKeyModal-editName" + fullWidth + placeholder="Type a name for your API key" + onChange={(event) => setKeyName(event.currentTarget.value)} + value={keyName} + isLoading={isLoading} + /> + </EuiFormRow> + </EuiFlexItem> + + <EuiFlexItem grow={false}> + <EuiButton + data-telemetry-id="entSearchContent-analyticss-api-generateAnalyticsApiKeyModal-generateApiKeyButton" + data-test-subj="generateApiKeyButton" + iconSide="left" + iconType="plusInCircle" + fill + onClick={() => { + makeRequest({ + collectionName, + keyName: keyName.trim(), + }); + }} + disabled={keyName.trim().length <= 0} + > + {i18n.translate( + 'xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.generateButton', + { + defaultMessage: 'Generate key', + } + )} + </EuiButton> + </EuiFlexItem> + </> + ) : ( + <EuiFlexItem> + <EuiFormLabel>{keyName}</EuiFormLabel> + <EuiSpacer size="xs" /> + <EuiFlexGroup alignItems="center"> + <EuiFlexItem> + <EuiCodeBlock + aria-label={keyName} + fontSize="m" + paddingSize="m" + color="dark" + isCopyable + > + {apiKey} + </EuiCodeBlock> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiButtonIcon + data-telemetry-id="entSearchContent-analyticss-api-generateAnalyticsApiKeyModal-csvDownloadButton" + aria-label={i18n.translate( + 'xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.csvDownloadButton', + { defaultMessage: 'Download API key' } + )} + iconType="download" + href={encodeURI(`data:text/csv;charset=utf-8,${apiKey}`)} + download={`${keyName}.csv`} + /> + </EuiFlexItem> + </EuiFlexGroup> + </EuiFlexItem> + )} + </EuiFlexGroup> + </EuiFlexItem> + <EuiFlexItem> + <EuiFlexGroup direction="row"> + <EuiFlexItem> + <EuiText size="s" color="#006bb8"> + <p> + {i18n.translate( + 'xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.apiKeyWarning', + { + defaultMessage: + "Elastic does not store API keys. Once generated, you'll only be able to view the key one time. Make sure you save it somewhere secure. If you lose access to it you'll need to generate a new API key from this screen.", + } + )} + </p> + </EuiText> + </EuiFlexItem> + </EuiFlexGroup> + </EuiFlexItem> + </EuiFlexGroup> + </EuiPanel> + </> + </EuiModalBody> + <EuiModalFooter> + {apiKey ? ( + <EuiButton + data-telemetry-id="entSearchContent-analyticss-api-generateAnalyticsApiKeyModal-done" + fill + onClick={onClose} + > + {i18n.translate( + 'xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.done', + { + defaultMessage: 'Done', + } + )} + </EuiButton> + ) : ( + <EuiButtonEmpty + data-telemetry-id="entSearchContent-analyticss-api-generateAnalyticsApiKeyModal-cancel" + onClick={onClose} + > + {i18n.translate( + 'xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.cancel', + { + defaultMessage: 'Cancel', + } + )} + </EuiButtonEmpty> + )} + </EuiModalFooter> + </EuiModal> + ); +}; diff --git a/x-pack/plugins/enterprise_search/server/lib/analytics/create_api_key.test.ts b/x-pack/plugins/enterprise_search/server/lib/analytics/create_api_key.test.ts new file mode 100644 index 0000000000000..fa0130e761962 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/analytics/create_api_key.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { IScopedClusterClient } from '@kbn/core/server'; + +import { createApiKey } from './create_api_key'; + +describe('createApiKey lib function', () => { + const createResponse = { + api_key: 'ui2lp2axTNmsyakw9tvNnw', + encoded: 'VnVhQ2ZHY0JDZGJrUW0tZTVhT3g6dWkybHAyYXhUTm1zeWFrdzl0dk5udw==', + id: 'VuaCfGcBCdbkQm-e5aOx', + name: 'website key', + }; + + const mockClient = { + asCurrentUser: { + security: { + createApiKey: jest.fn().mockReturnValue(createResponse), + }, + }, + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should create an api key via the security plugin', async () => { + await expect( + createApiKey(mockClient as unknown as IScopedClusterClient, 'website', 'website key') + ).resolves.toEqual(createResponse); + + expect(mockClient.asCurrentUser.security.createApiKey).toHaveBeenCalledWith({ + name: 'website key', + role_descriptors: { + 'website-key-role': { + cluster: ['post_behavioral_analytics_event'], + }, + }, + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/server/lib/analytics/create_api_key.ts b/x-pack/plugins/enterprise_search/server/lib/analytics/create_api_key.ts new file mode 100644 index 0000000000000..6e7a19f95fc06 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/analytics/create_api_key.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 { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; + +export const createApiKey = async (client: IScopedClusterClient, name: string, keyName: string) => { + return await client.asCurrentUser.security.createApiKey({ + name: keyName, + role_descriptors: { + [`${name}-key-role`]: { + cluster: ['post_behavioral_analytics_event'], + }, + }, + }); +}; diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/analytics.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/analytics.ts index 717137950ab63..31d1f4cc123c9 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/analytics.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/analytics.ts @@ -15,6 +15,7 @@ import { i18n } from '@kbn/i18n'; import { ErrorCode } from '../../../common/types/error_codes'; import { addAnalyticsCollection } from '../../lib/analytics/add_analytics_collection'; import { analyticsEventsIndexExists } from '../../lib/analytics/analytics_events_index_exists'; +import { createApiKey } from '../../lib/analytics/create_api_key'; import { deleteAnalyticsCollectionById } from '../../lib/analytics/delete_analytics_collection'; import { fetchAnalyticsCollections } from '../../lib/analytics/fetch_analytics_collection'; import { RouteDependencies } from '../../plugin'; @@ -84,6 +85,32 @@ export function registerAnalyticsRoutes({ }) ); + router.post( + { + path: '/internal/enterprise_search/analytics/collections/{name}/api_key', + validate: { + body: schema.object({ + keyName: schema.string(), + }), + params: schema.object({ + name: schema.string(), + }), + }, + }, + elasticsearchErrorHandler(log, async (context, request, response) => { + const collectionName = decodeURIComponent(request.params.name); + const { keyName } = request.body; + const { client } = (await context.core).elasticsearch; + + const apiKey = await createApiKey(client, collectionName, keyName); + + return response.ok({ + body: { apiKey }, + headers: { 'content-type': 'application/json' }, + }); + }) + ); + router.post( { path: '/internal/enterprise_search/analytics/collections',