From c7f15fc82c760c3b6247f5d57ea74da35fc22dd6 Mon Sep 17 00:00:00 2001 From: Pierre Gayvallet Date: Thu, 4 Jan 2024 09:29:39 +0100 Subject: [PATCH 001/100] [security solution] fix darkMode access (#173894) ## Summary Part of https://github.com/elastic/kibana/issues/173529 Adapt theme access based on `uiSettings.get('theme:darkMode')` with the correct approach of using `core.theme` or the `useDarkMode` react hook. --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/security_solution/common/constants.ts | 1 - x-pack/plugins/security_solution/public/app/app.tsx | 6 +++--- .../public/common/components/charts/common.test.tsx | 6 +++--- .../public/common/components/charts/common.tsx | 5 ++--- .../public/common/lib/kibana/__mocks__/index.ts | 3 +++ .../public/common/lib/kibana/kibana_react.mock.ts | 6 +----- .../public/common/lib/kibana/kibana_react.ts | 2 ++ .../public/common/lib/theme/use_eui_theme.tsx | 5 ++--- .../public/common/mock/endpoint/app_root_provider.tsx | 5 +++-- .../public/explore/network/components/details/index.tsx | 5 ++--- .../public/overview/components/host_overview/index.tsx | 5 ++--- .../public/overview/components/user_overview/index.tsx | 5 ++--- .../public/resolver/view/symbol_definitions.tsx | 4 ++-- 13 files changed, 27 insertions(+), 31 deletions(-) diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index 52a2bcfc859b1..e3fe732373798 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -31,7 +31,6 @@ export const ADD_THREAT_INTELLIGENCE_DATA_PATH = `/app/integrations/browse/threa export const DEFAULT_BYTES_FORMAT = 'format:bytes:defaultPattern' as const; export const DEFAULT_DATE_FORMAT = 'dateFormat' as const; export const DEFAULT_DATE_FORMAT_TZ = 'dateFormat:tz' as const; -export const DEFAULT_DARK_MODE = 'theme:darkMode' as const; export const DEFAULT_INDEX_KEY = 'securitySolution:defaultIndex' as const; export const DEFAULT_NUMBER_FORMAT = 'format:number:defaultPattern' as const; export const DEFAULT_DATA_VIEW_ID = 'security-solution' as const; diff --git a/x-pack/plugins/security_solution/public/app/app.tsx b/x-pack/plugins/security_solution/public/app/app.tsx index ad99133f266ac..ede4908540ad2 100644 --- a/x-pack/plugins/security_solution/public/app/app.tsx +++ b/x-pack/plugins/security_solution/public/app/app.tsx @@ -20,11 +20,11 @@ import { KibanaErrorBoundary, KibanaErrorBoundaryProvider } from '@kbn/shared-ux import { NavigationProvider } from '@kbn/security-solution-navigation'; import { UpsellingProvider } from '../common/components/upselling_provider'; import { ManageUserInfo } from '../detections/components/user_info'; -import { DEFAULT_DARK_MODE, APP_NAME } from '../../common/constants'; +import { APP_NAME } from '../../common/constants'; import { ErrorToastDispatcher } from '../common/components/error_toast_dispatcher'; import { MlCapabilitiesProvider } from '../common/components/ml/permissions/ml_capabilities_provider'; import { GlobalToaster, ManageGlobalToaster } from '../common/components/toasters'; -import { KibanaContextProvider, useKibana, useUiSetting$ } from '../common/lib/kibana'; +import { KibanaContextProvider, useKibana, useDarkMode } from '../common/lib/kibana'; import type { State } from '../common/store'; import type { StartServices } from '../types'; import { PageRouter } from './routes'; @@ -57,7 +57,7 @@ const StartAppComponent: FC = ({ upselling, } = services; - const [darkMode] = useUiSetting$(DEFAULT_DARK_MODE); + const darkMode = useDarkMode(); return ( diff --git a/x-pack/plugins/security_solution/public/common/components/charts/common.test.tsx b/x-pack/plugins/security_solution/public/common/components/charts/common.test.tsx index 71c3c0793d72b..20dfc140c4138 100644 --- a/x-pack/plugins/security_solution/public/common/components/charts/common.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/charts/common.test.tsx @@ -9,7 +9,7 @@ import { shallow } from 'enzyme'; import React from 'react'; import { renderHook } from '@testing-library/react-hooks'; -import { useUiSetting } from '../../lib/kibana'; +import { useDarkMode } from '../../lib/kibana'; import type { ChartSeriesData } from './common'; import { checkIfAllValuesAreZero, @@ -178,14 +178,14 @@ describe('checkIfAllValuesAreZero', () => { }); it('should return light baseTheme when isDarkMode false', () => { - (useUiSetting as jest.Mock).mockImplementation(() => false); + (useDarkMode as jest.Mock).mockImplementation(() => false); const { result } = renderHook(() => useThemes()); expect(result.current.baseTheme).toBe(LEGACY_LIGHT_THEME); }); it('should return dark baseTheme when isDarkMode true', () => { - (useUiSetting as jest.Mock).mockImplementation(() => true); + (useDarkMode as jest.Mock).mockImplementation(() => true); const { result } = renderHook(() => useThemes()); expect(result.current.baseTheme).toBe(LEGACY_DARK_THEME); diff --git a/x-pack/plugins/security_solution/public/common/components/charts/common.tsx b/x-pack/plugins/security_solution/public/common/components/charts/common.tsx index 73fab4a3a8890..05edabafcff7c 100644 --- a/x-pack/plugins/security_solution/public/common/components/charts/common.tsx +++ b/x-pack/plugins/security_solution/public/common/components/charts/common.tsx @@ -22,8 +22,7 @@ import { EuiFlexGroup } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; -import { DEFAULT_DARK_MODE } from '../../../../common/constants'; -import { useUiSetting } from '../../lib/kibana'; +import { useDarkMode } from '../../lib/kibana'; export const defaultChartHeight = '100%'; export const defaultChartWidth = '100%'; @@ -113,7 +112,7 @@ const theme: PartialTheme = { }, }; export const useThemes = (): { baseTheme: Theme; theme: PartialTheme } => { - const isDarkMode = useUiSetting(DEFAULT_DARK_MODE); + const isDarkMode = useDarkMode(); // TODO connect to charts.theme service see src/plugins/charts/public/services/theme/README.md const baseTheme = isDarkMode ? LEGACY_DARK_THEME : LEGACY_LIGHT_THEME; return { diff --git a/x-pack/plugins/security_solution/public/common/lib/kibana/__mocks__/index.ts b/x-pack/plugins/security_solution/public/common/lib/kibana/__mocks__/index.ts index a0f59fb18f3f8..27d48a9ff6417 100644 --- a/x-pack/plugins/security_solution/public/common/lib/kibana/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kibana/__mocks__/index.ts @@ -85,6 +85,9 @@ export const useKibana = jest.fn().mockReturnValue({ }); export const useUiSetting = jest.fn(createUseUiSettingMock()); export const useUiSetting$ = jest.fn(createUseUiSetting$Mock()); +export const useDarkMode = jest + .fn() + .mockImplementation((defaultValue?: boolean) => defaultValue ?? false); export const useHttp = jest.fn().mockReturnValue(createStartServicesMock().http); export const useTimeZone = jest.fn(); export const useDateFormat = jest.fn().mockReturnValue('MMM D, YYYY @ HH:mm:ss.SSS'); diff --git a/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.mock.ts b/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.mock.ts index ffbd26b97028a..b2cda32060382 100644 --- a/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.mock.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.mock.ts @@ -18,7 +18,6 @@ import { DEFAULT_APP_REFRESH_INTERVAL, DEFAULT_APP_TIME_RANGE, DEFAULT_BYTES_FORMAT, - DEFAULT_DARK_MODE, DEFAULT_DATE_FORMAT, DEFAULT_DATE_FORMAT_TZ, DEFAULT_FROM, @@ -69,7 +68,6 @@ const mockUiSettings: Record = { [DEFAULT_BYTES_FORMAT]: '0,0.[0]b', [DEFAULT_DATE_FORMAT_TZ]: 'UTC', [DEFAULT_DATE_FORMAT]: 'MMM D, YYYY @ HH:mm:ss.SSS', - [DEFAULT_DARK_MODE]: false, [DEFAULT_RULES_TABLE_REFRESH_SETTING]: { on: DEFAULT_RULE_REFRESH_INTERVAL_ON, value: DEFAULT_RULE_REFRESH_INTERVAL_VALUE, @@ -199,9 +197,7 @@ export const createStartServicesMock = ( locator, }, telemetry: {}, - theme: { - theme$: themeServiceMock.createTheme$(), - }, + theme: themeServiceMock.createSetupContract(), timelines: { getLastUpdated: jest.fn(), getFieldBrowser: jest.fn(), diff --git a/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.ts b/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.ts index 4878ee2a30919..8590cfe98dc17 100644 --- a/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.ts @@ -10,6 +10,7 @@ import { useKibana, useUiSetting, useUiSetting$, + useDarkMode, withKibana, } from '@kbn/kibana-react-plugin/public'; import type { ApmBase } from '@elastic/apm-rum'; @@ -23,5 +24,6 @@ export { useTypedKibana as useKibana, useUiSetting, useUiSetting$, + useDarkMode, withKibana, }; diff --git a/x-pack/plugins/security_solution/public/common/lib/theme/use_eui_theme.tsx b/x-pack/plugins/security_solution/public/common/lib/theme/use_eui_theme.tsx index e890d9fe6d650..41a3076d52c88 100644 --- a/x-pack/plugins/security_solution/public/common/lib/theme/use_eui_theme.tsx +++ b/x-pack/plugins/security_solution/public/common/lib/theme/use_eui_theme.tsx @@ -7,10 +7,9 @@ import { euiLightVars as lightTheme, euiDarkVars as darkTheme } from '@kbn/ui-theme'; -import { DEFAULT_DARK_MODE } from '../../../../common/constants'; -import { useUiSetting$ } from '../kibana'; +import { useDarkMode } from '../kibana'; export const useEuiTheme = () => { - const [darkMode] = useUiSetting$(DEFAULT_DARK_MODE); + const darkMode = useDarkMode(); return darkMode ? darkTheme : lightTheme; }; diff --git a/x-pack/plugins/security_solution/public/common/mock/endpoint/app_root_provider.tsx b/x-pack/plugins/security_solution/public/common/mock/endpoint/app_root_provider.tsx index 8c65ba84ff871..e32297f729ec3 100644 --- a/x-pack/plugins/security_solution/public/common/mock/endpoint/app_root_provider.tsx +++ b/x-pack/plugins/security_solution/public/common/mock/endpoint/app_root_provider.tsx @@ -37,8 +37,9 @@ export const AppRootProvider = memo<{ queryClient: QueryClient; children: ReactNode | ReactNode[]; }>(({ store, history, coreStart, depsStart: { data }, queryClient, startServices, children }) => { - const { uiSettings } = coreStart; - const isDarkMode = useObservable(uiSettings.get$('theme:darkMode')); + const { theme: themeStart } = coreStart; + const theme = useObservable(themeStart.theme$, themeStart.getTheme()); + const isDarkMode = theme.darkMode; return ( diff --git a/x-pack/plugins/security_solution/public/explore/network/components/details/index.tsx b/x-pack/plugins/security_solution/public/explore/network/components/details/index.tsx index 62c6a6f462d14..1c909a8eff31b 100644 --- a/x-pack/plugins/security_solution/public/explore/network/components/details/index.tsx +++ b/x-pack/plugins/security_solution/public/explore/network/components/details/index.tsx @@ -8,9 +8,8 @@ import { euiLightVars as lightTheme, euiDarkVars as darkTheme } from '@kbn/ui-theme'; import React from 'react'; -import { DEFAULT_DARK_MODE } from '../../../../../common/constants'; import type { DescriptionList } from '../../../../../common/utility_types'; -import { useUiSetting$ } from '../../../../common/lib/kibana'; +import { useDarkMode } from '../../../../common/lib/kibana'; import type { FlowTargetSourceDest, NetworkDetailsStrategyResponse, @@ -79,7 +78,7 @@ export const IpOverview = React.memo( }) => { const capabilities = useMlCapabilities(); const userPermissions = hasMlUserPermissions(capabilities); - const [darkMode] = useUiSetting$(DEFAULT_DARK_MODE); + const darkMode = useDarkMode(); const typeData = data[flowTarget]; const column: DescriptionList[] = [ { diff --git a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx index a6409c587e0a6..92ff143585117 100644 --- a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx @@ -13,9 +13,8 @@ import styled from 'styled-components'; import { useRiskScore } from '../../../entity_analytics/api/hooks/use_risk_score'; import type { HostItem } from '../../../../common/search_strategy'; import { buildHostNamesFilter, RiskScoreEntity } from '../../../../common/search_strategy'; -import { DEFAULT_DARK_MODE } from '../../../../common/constants'; import type { DescriptionList } from '../../../../common/utility_types'; -import { useUiSetting$ } from '../../../common/lib/kibana'; +import { useDarkMode } from '../../../common/lib/kibana'; import { getEmptyTagValue } from '../../../common/components/empty_value'; import { DefaultFieldRenderer, @@ -84,7 +83,7 @@ export const HostOverview = React.memo( }) => { const capabilities = useMlCapabilities(); const userPermissions = hasMlUserPermissions(capabilities); - const [darkMode] = useUiSetting$(DEFAULT_DARK_MODE); + const darkMode = useDarkMode(); const filterQuery = useMemo( () => (hostName ? buildHostNamesFilter([hostName]) : undefined), [hostName] diff --git a/x-pack/plugins/security_solution/public/overview/components/user_overview/index.tsx b/x-pack/plugins/security_solution/public/overview/components/user_overview/index.tsx index 572e4aab7e6df..bd9e56dffee8d 100644 --- a/x-pack/plugins/security_solution/public/overview/components/user_overview/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/user_overview/index.tsx @@ -12,9 +12,8 @@ import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; import { useRiskScore } from '../../../entity_analytics/api/hooks/use_risk_score'; import { buildUserNamesFilter, RiskScoreEntity } from '../../../../common/search_strategy'; -import { DEFAULT_DARK_MODE } from '../../../../common/constants'; import type { DescriptionList } from '../../../../common/utility_types'; -import { useUiSetting$ } from '../../../common/lib/kibana'; +import { useDarkMode } from '../../../common/lib/kibana'; import { getEmptyTagValue } from '../../../common/components/empty_value'; import { DefaultFieldRenderer } from '../../../timelines/components/field_renderers/field_renderers'; import { @@ -82,7 +81,7 @@ export const UserOverview = React.memo( }) => { const capabilities = useMlCapabilities(); const userPermissions = hasMlUserPermissions(capabilities); - const [darkMode] = useUiSetting$(DEFAULT_DARK_MODE); + const darkMode = useDarkMode(); const filterQuery = useMemo( () => (userName ? buildUserNamesFilter([userName]) : undefined), [userName] diff --git a/x-pack/plugins/security_solution/public/resolver/view/symbol_definitions.tsx b/x-pack/plugins/security_solution/public/resolver/view/symbol_definitions.tsx index 926227f6fcfd7..8576c6a364a96 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/symbol_definitions.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/symbol_definitions.tsx @@ -8,7 +8,7 @@ import React, { memo } from 'react'; import styled from 'styled-components'; import { i18n } from '@kbn/i18n'; -import { useUiSetting } from '@kbn/kibana-react-plugin/public'; +import { useDarkMode } from '@kbn/kibana-react-plugin/public'; import { useSymbolIDs } from './use_symbol_ids'; import { usePaintServerIDs } from './use_paint_server_ids'; @@ -435,7 +435,7 @@ const SymbolsAndShapes = memo(({ id, isDarkMode }: { id: string; isDarkMode: boo */ // eslint-disable-next-line react/display-name export const SymbolDefinitions = memo(({ id }: { id: string }) => { - const isDarkMode = useUiSetting('theme:darkMode'); + const isDarkMode = useDarkMode(); return ( From e2906aee878b25494acbd02f950fe8d4e4abbc9b Mon Sep 17 00:00:00 2001 From: Angela Chuang <6295984+angorayc@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:35:05 +0800 Subject: [PATCH 002/100] [SecuritySolution] Disable Panel Settings for visualization context menu (#174183) ## Summary `Panel Settings` action is not compatible with Security Solution ([bug](https://github.com/elastic/kibana/issues/168670)), removing them in this PR. Steps to verify: 1. Visit network / hosts / users / rules / alerts page 2. Find a visualization rendered with Lens Embeddable 3. Click on `...`, and find `Panel settings` should not exist ![Screenshot 2024-01-03 at 22 41 51](https://github.com/elastic/kibana/assets/6295984/f97866a4-0d97-42f5-94d1-46e1b4f3395e) - [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 --- .../visualization_actions/lens_embeddable.test.tsx | 7 +++++++ .../components/visualization_actions/lens_embeddable.tsx | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.test.tsx b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.test.tsx index c7607cd1046df..92f394006d8e9 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.test.tsx @@ -20,6 +20,7 @@ import { kpiHostMetricLensAttributes } from './lens_attributes/hosts/kpi_host_me import { LensEmbeddable } from './lens_embeddable'; import { useKibana } from '../../lib/kibana'; import { useActions } from './use_actions'; +import { ACTION_CUSTOMIZE_PANEL } from '@kbn/embeddable-plugin/public'; const mockActions = [ { id: 'inspect' }, @@ -128,4 +129,10 @@ describe('LensEmbeddable', () => { expect(mockEmbeddableComponent.mock.calls[0][0].syncTooltips).toEqual(false); expect(mockEmbeddableComponent.mock.calls[0][0].syncCursor).toEqual(false); }); + + it('should not render Panel settings action', () => { + expect( + mockEmbeddableComponent.mock.calls[0][0].disabledActions.includes(ACTION_CUSTOMIZE_PANEL) + ).toBeTruthy(); + }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.tsx b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.tsx index fdaa006e15f56..69d171467f996 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.tsx +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.tsx @@ -9,7 +9,7 @@ import React, { useCallback, useMemo, useState } from 'react'; import { useDispatch } from 'react-redux'; import { FormattedMessage } from '@kbn/i18n-react'; -import { ViewMode } from '@kbn/embeddable-plugin/public'; +import { ACTION_CUSTOMIZE_PANEL, ViewMode } from '@kbn/embeddable-plugin/public'; import styled from 'styled-components'; import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; import type { RangeFilterParams } from '@kbn/es-query'; @@ -29,6 +29,7 @@ import { SourcererScopeName } from '../../store/sourcerer/model'; import { VisualizationActions } from './actions'; const HOVER_ACTIONS_PADDING = 24; +const DISABLED_ACTIONS = [ACTION_CUSTOMIZE_PANEL]; const LensComponentWrapper = styled.div<{ $height?: number; @@ -278,6 +279,7 @@ const LensEmbeddableComponent: React.FC = ({ style={style} timeRange={timerange} attributes={attributes} + disabledActions={DISABLED_ACTIONS} onLoad={onLoadCallback} onBrushEnd={updateDateRange} onFilter={onFilterCallback} From f8f0d87d5b6d8e657cf30153039fe8054311d42c Mon Sep 17 00:00:00 2001 From: Marta Bondyra <4283304+mbondyra@users.noreply.github.com> Date: Thu, 4 Jan 2024 11:51:48 +0100 Subject: [PATCH 003/100] [Lens] do not allow to save incorrect state in inline Lens editor (#172819) ## Summary Fixes https://github.com/elastic/kibana/issues/168445 We follow the approach: 1. if we can render we are able to save even with errors 2. If we cannot render, we cannot save There are 3 cases we have to think when approaching this task. 1. When the error comes from the request (for example, incorrect KQL in 'filter by' or wrong response from ES) We don't catch those cases in Lens app so I didn't fix it here either. It would be very difficult to do so. 2. When the chart cannot be rendered (whether there's a missing dimension or errors stop the expression to be generated) Screenshot 2023-10-16 at 13 30 32 3. When the chart has errors but can be rendered We allow saving in this case. Screenshot 2023-10-17 at 15 02 47 --------- Co-authored-by: Stratoula Kalafateli --- .../shared/edit_on_the_fly/flyout_wrapper.tsx | 4 +- .../lens_configuration_flyout.test.tsx | 65 +++++++++++++++---- .../lens_configuration_flyout.tsx | 56 ++++++++++++++-- .../shared/edit_on_the_fly/types.ts | 2 +- .../workspace_panel/workspace_panel.tsx | 20 +++--- x-pack/plugins/lens/public/utils.ts | 2 + 6 files changed, 118 insertions(+), 31 deletions(-) diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/flyout_wrapper.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/flyout_wrapper.tsx index f9a6ac0ce397b..009d21d65eb57 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/flyout_wrapper.tsx +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/flyout_wrapper.tsx @@ -31,8 +31,8 @@ export const FlyoutWrapper = ({ isScrollable, displayFlyoutHeader, language, - attributesChanged, isNewPanel, + isSaveable, onCancel, navigateToLensEditor, onApply, @@ -153,7 +153,7 @@ export const FlyoutWrapper = ({ aria-label={i18n.translate('xpack.lens.config.applyFlyoutAriaLabel', { defaultMessage: 'Apply changes', })} - disabled={Boolean(isNewPanel) ? false : !attributesChanged} + disabled={Boolean(isNewPanel) ? false : !isSaveable} iconType="check" data-test-subj="applyFlyoutButton" > diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.test.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.test.tsx index 6aad89b50ef0c..bda603bb0909d 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.test.tsx +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.test.tsx @@ -36,20 +36,21 @@ const lensAttributes = { }, references: [], } as unknown as TypedLensByValueInput['attributes']; +const mockStartDependencies = + createMockStartDependencies() as unknown as LensPluginStartDependencies; +const data = mockDataPlugin(); +(data.query.timefilter.timefilter.getTime as jest.Mock).mockReturnValue({ + from: 'now-2m', + to: 'now', +}); +const startDependencies = { + ...mockStartDependencies, + data, +}; +const datasourceMap = mockDatasourceMap(); +const visualizationMap = mockVisualizationMap(); describe('LensEditConfigurationFlyout', () => { - const mockStartDependencies = - createMockStartDependencies() as unknown as LensPluginStartDependencies; - const data = mockDataPlugin(); - (data.query.timefilter.timefilter.getTime as jest.Mock).mockReturnValue({ - from: 'now-2m', - to: 'now', - }); - const startDependencies = { - ...mockStartDependencies, - data, - }; - function renderConfigFlyout( propsOverrides: Partial = {}, query?: Query | AggregateQuery @@ -60,8 +61,8 @@ describe('LensEditConfigurationFlyout', () => { updatePanelState={jest.fn()} coreStart={coreMock.createStart()} startDependencies={startDependencies} - datasourceMap={mockDatasourceMap()} - visualizationMap={mockVisualizationMap()} + datasourceMap={datasourceMap} + visualizationMap={visualizationMap} closeFlyout={jest.fn()} datasourceId={'testDatasource' as EditConfigPanelProps['datasourceId']} {...propsOverrides} @@ -195,4 +196,40 @@ describe('LensEditConfigurationFlyout', () => { expect(screen.getByTestId('InlineEditingESQLEditor')).toBeInTheDocument(); expect(screen.getByTestId('InlineEditingSuggestions')).toBeInTheDocument(); }); + it('save button is disabled if no changes have been made', async () => { + const updateByRefInputSpy = jest.fn(); + const saveByRefSpy = jest.fn(); + const newProps = { + closeFlyout: jest.fn(), + updateByRefInput: updateByRefInputSpy, + savedObjectId: 'id', + saveByRef: saveByRefSpy, + attributes: lensAttributes, + }; + // todo: replace testDatasource with formBased or textBased as it's the only ones accepted + // @ts-ignore + newProps.attributes.state.datasourceStates.testDatasource = 'state'; + renderConfigFlyout(newProps); + expect(screen.getByRole('button', { name: /apply changes/i })).toBeDisabled(); + }); + it('save button should be disabled if expression cannot be generated', async () => { + const updateByRefInputSpy = jest.fn(); + const saveByRefSpy = jest.fn(); + const newProps = { + closeFlyout: jest.fn(), + updateByRefInput: updateByRefInputSpy, + savedObjectId: 'id', + saveByRef: saveByRefSpy, + datasourceMap: { + ...datasourceMap, + testDatasource: { + ...datasourceMap.testDatasource, + toExpression: jest.fn(() => null), + }, + }, + }; + + renderConfigFlyout(newProps); + expect(screen.getByRole('button', { name: /apply changes/i })).toBeDisabled(); + }); }); diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx index 39801f41c391c..e3df96840c883 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx @@ -27,6 +27,7 @@ import { import type { AggregateQuery, Query } from '@kbn/es-query'; import { TextBasedLangEditor } from '@kbn/text-based-languages/public'; import { DefaultInspectorAdapters } from '@kbn/expressions-plugin/common'; +import { buildExpression } from '../../../editor_frame_service/editor_frame/expression_helpers'; import { useLensSelector, selectFramePublicAPI, @@ -34,7 +35,7 @@ import { useLensDispatch, } from '../../../state_management'; import type { TypedLensByValueInput } from '../../../embeddable/embeddable_component'; -import { extractReferencesFromState } from '../../../utils'; +import { EXPRESSION_BUILD_ERROR_ID, extractReferencesFromState } from '../../../utils'; import { LayerConfiguration } from './layer_configuration_section'; import type { EditConfigPanelProps } from './types'; import { FlyoutWrapper } from './flyout_wrapper'; @@ -76,12 +77,13 @@ export function LensEditConfigurationFlyout({ const [isSuggestionsAccordionOpen, setIsSuggestionsAccordionOpen] = useState(false); const datasourceState = attributes.state.datasourceStates[datasourceId]; const activeDatasource = datasourceMap[datasourceId]; - const { datasourceStates, visualization, isLoading, annotationGroups } = useLensSelector( - (state) => state.lens - ); + + const { datasourceStates, visualization, isLoading, annotationGroups, searchSessionId } = + useLensSelector((state) => state.lens); // use the latest activeId, but fallback to attributes const activeVisualization = visualizationMap[visualization.activeId ?? attributes.visualizationType]; + const framePublicAPI = useLensSelector((state) => selectFramePublicAPI(state, datasourceMap)); const suggestsLimitedColumns = activeDatasource?.suggestsLimitedColumns?.(datasourceState); @@ -272,6 +274,48 @@ export function LensEditConfigurationFlyout({ ] ); + const isSaveable = useMemo(() => { + if (!attributesChanged) { + return false; + } + if (!visualization.state || !visualization.activeId) { + return false; + } + const visualizationErrors = getUserMessages(['visualization'], { + severity: 'error', + }); + // shouldn't build expression if there is any type of error other than an expression build error + // (in which case we try again every time because the config might have changed) + if (visualizationErrors.every((error) => error.uniqueId === EXPRESSION_BUILD_ERROR_ID)) { + return Boolean( + buildExpression({ + visualization: activeVisualization, + visualizationState: visualization.state, + datasourceMap, + datasourceStates, + datasourceLayers: framePublicAPI.datasourceLayers, + indexPatterns: framePublicAPI.dataViews.indexPatterns, + dateRange: framePublicAPI.dateRange, + nowInstant: startDependencies.data.nowProvider.get(), + searchSessionId, + }) + ); + } + }, [ + attributesChanged, + activeVisualization, + datasourceMap, + datasourceStates, + framePublicAPI.dataViews.indexPatterns, + framePublicAPI.dateRange, + framePublicAPI.datasourceLayers, + searchSessionId, + startDependencies.data.nowProvider, + visualization.activeId, + visualization.state, + getUserMessages, + ]); + const textBasedMode = isOfAggregateQueryType(query) ? getAggregateQueryMode(query) : undefined; if (isLoading) return null; @@ -285,8 +329,8 @@ export function LensEditConfigurationFlyout({ navigateToLensEditor={navigateToLensEditor} onApply={onApply} isScrollable={true} - attributesChanged={attributesChanged} isNewPanel={isNewPanel} + isSaveable={isSaveable} > diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/types.ts b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/types.ts index 12533bfbe6cd4..6b5a2bb501275 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/types.ts +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/types.ts @@ -24,8 +24,8 @@ export interface FlyoutWrapperProps { isScrollable: boolean; displayFlyoutHeader?: boolean; language?: string; - attributesChanged?: boolean; isNewPanel?: boolean; + isSaveable?: boolean; onCancel?: () => void; onApply?: () => void; navigateToLensEditor?: () => void; 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 18ea4791d6847..8b7705260c1e4 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 @@ -72,7 +72,11 @@ import { selectExecutionContextSearch, } from '../../../state_management'; import type { LensInspector } from '../../../lens_inspector_service'; -import { inferTimeField, DONT_CLOSE_DIMENSION_CONTAINER_ON_CLICK_CLASS } from '../../../utils'; +import { + inferTimeField, + DONT_CLOSE_DIMENSION_CONTAINER_ON_CLICK_CLASS, + EXPRESSION_BUILD_ERROR_ID, +} from '../../../utils'; import { setChangesApplied } from '../../../state_management/lens_slice'; import { WorkspaceErrors } from './workspace_errors'; @@ -113,8 +117,6 @@ const executionContext: KibanaExecutionContext = { }, }; -const EXPRESSION_BUILD_ERROR_ID = 'expression_build_error'; - export const WorkspacePanel = React.memo(function WorkspacePanel(props: WorkspacePanelProps) { const { getSuggestionForField, ...restProps } = props; @@ -295,11 +297,13 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ ? visualizationMap[visualization.activeId] : null; - const workspaceErrors = useCallback(() => { - return getUserMessages(['visualization', 'visualizationInEditor'], { - severity: 'error', - }); - }, [getUserMessages]); + const workspaceErrors = useCallback( + () => + getUserMessages(['visualization', 'visualizationInEditor'], { + severity: 'error', + }), + [getUserMessages] + ); // if the expression is undefined, it means we hit an error that should be displayed to the user const unappliedExpression = useMemo(() => { diff --git a/x-pack/plugins/lens/public/utils.ts b/x-pack/plugins/lens/public/utils.ts index 86c769444c69c..d16dacada6fe1 100644 --- a/x-pack/plugins/lens/public/utils.ts +++ b/x-pack/plugins/lens/public/utils.ts @@ -429,3 +429,5 @@ export const getColorMappingDefaults = () => { } return { ...DEFAULT_COLOR_MAPPING_CONFIG }; }; + +export const EXPRESSION_BUILD_ERROR_ID = 'expression_build_error'; From af4dcb419a433f269a62a51a8fa958c5aee993ae Mon Sep 17 00:00:00 2001 From: Maryam Saeidi Date: Thu, 4 Jan 2024 12:07:00 +0100 Subject: [PATCH 004/100] [Metric threshold] Remove disabling missing group for document count aggregation (#173898) Closes #173396 ## Summary This PR removes disabling missing group settings when aggregation is document count because it also works as expected for this case. ([more info](https://github.com/elastic/kibana/issues/173396#issuecomment-1867399404)) --- .../public/alerting/metric_threshold/components/expression.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx index 029cecdcb1036..814a968d9718e 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx @@ -479,7 +479,7 @@ export const Expressions: React.FC = (props) => { } - disabled={disableNoData || !hasGroupBy} + disabled={!hasGroupBy} checked={Boolean(hasGroupBy && ruleParams.alertOnGroupDisappear)} onChange={(e) => setRuleParams('alertOnGroupDisappear', e.target.checked)} /> From aa372f48844870bb4e93e9e512d06e1bdfc95b76 Mon Sep 17 00:00:00 2001 From: Panagiota Mitsopoulou Date: Thu, 4 Jan 2024 12:28:13 +0100 Subject: [PATCH 005/100] Refactor: Use uiSettings directly from services prop (#174170) Refactors according to this [comment](https://github.com/elastic/kibana/pull/172498#discussion_r1416947582) --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../apm/public/components/app/alerts_overview/index.tsx | 8 +++++++- x-pack/plugins/apm/public/plugin.ts | 3 +++ x-pack/plugins/apm/tsconfig.json | 3 ++- .../components/alert_search_bar/alert_search_bar.test.tsx | 3 +++ .../components/alert_search_bar/alert_search_bar.tsx | 4 +--- .../alert_search_bar/alert_search_bar_with_url_sync.tsx | 3 ++- .../public/components/alert_search_bar/types.ts | 3 ++- .../plugins/observability/public/pages/alerts/alerts.tsx | 3 ++- x-pack/plugins/observability/tsconfig.json | 3 ++- 9 files changed, 24 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx b/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx index dbf2d94b20699..b5ed35059bda9 100644 --- a/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx @@ -53,6 +53,7 @@ export function AlertsOverview() { timefilter: { timefilter: timeFilterService }, }, }, + uiSettings, } = services; const useToasts = () => notifications!.toasts; @@ -98,7 +99,12 @@ export function AlertsOverview() { rangeTo={rangeTo} rangeFrom={rangeFrom} status={alertStatusFilter} - services={{ timeFilterService, AlertsSearchBar, useToasts }} + services={{ + timeFilterService, + AlertsSearchBar, + useToasts, + uiSettings, + }} /> diff --git a/x-pack/plugins/apm/public/plugin.ts b/x-pack/plugins/apm/public/plugin.ts index 173e52e5955cd..065eba1b7e64f 100644 --- a/x-pack/plugins/apm/public/plugin.ts +++ b/x-pack/plugins/apm/public/plugin.ts @@ -70,6 +70,7 @@ import { UiActionsSetup, UiActionsStart } from '@kbn/ui-actions-plugin/public'; import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; import { UsageCollectionStart } from '@kbn/usage-collection-plugin/public'; import { DashboardStart } from '@kbn/dashboard-plugin/public'; +import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; import { from } from 'rxjs'; import { map } from 'rxjs/operators'; import type { ConfigSchema } from '.'; @@ -84,6 +85,7 @@ import { getLazyAPMPolicyEditExtension } from './components/fleet_integration/la import { featureCatalogueEntry } from './feature_catalogue_entry'; import { APMServiceDetailLocator } from './locator/service_detail_locator'; import { ITelemetryClient, TelemetryService } from './services/telemetry'; + export type ApmPluginSetup = ReturnType; export type ApmPluginStart = void; @@ -137,6 +139,7 @@ export interface ApmPluginStartDeps { observabilityAIAssistant: ObservabilityAIAssistantPluginStart; dashboard: DashboardStart; metricsDataAccess: MetricsDataPluginStart; + uiSettings: IUiSettingsClient; } const servicesTitle = i18n.translate('xpack.apm.navigation.servicesTitle', { diff --git a/x-pack/plugins/apm/tsconfig.json b/x-pack/plugins/apm/tsconfig.json index ba23f19f78c4a..83736c390ef83 100644 --- a/x-pack/plugins/apm/tsconfig.json +++ b/x-pack/plugins/apm/tsconfig.json @@ -107,7 +107,8 @@ "@kbn/elastic-agent-utils", "@kbn/shared-ux-link-redirect-app", "@kbn/observability-get-padded-alert-time-range-util", - "@kbn/core-lifecycle-server" + "@kbn/core-lifecycle-server", + "@kbn/core-ui-settings-browser" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.test.tsx b/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.test.tsx index 5937fd4f8f7aa..248731d8cab2a 100644 --- a/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.test.tsx +++ b/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.test.tsx @@ -8,6 +8,8 @@ import React from 'react'; import { waitFor } from '@testing-library/react'; import { timefilterServiceMock } from '@kbn/data-plugin/public/query/timefilter/timefilter_service.mock'; +import { uiSettingsServiceMock } from '@kbn/core-ui-settings-browser-mocks'; + import { ObservabilityAlertSearchBarProps, Services } from './types'; import { ObservabilityAlertSearchBar } from './alert_search_bar'; import { observabilityAlertFeatureIds } from '../../../common/constants'; @@ -33,6 +35,7 @@ describe('ObservabilityAlertSearchBar', () => { rangeFrom: 'now-15m', status: 'all', services: { + uiSettings: uiSettingsServiceMock.createStartContract(), timeFilterService: timefilterServiceMock.createStartContract().timefilter, AlertsSearchBar: getAlertsSearchBarMock.mockReturnValue(
diff --git a/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.tsx b/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.tsx index 74dfbe15d77f5..d27e32970f2fa 100644 --- a/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.tsx +++ b/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.tsx @@ -17,7 +17,6 @@ import { ALERT_STATUS_QUERY, DEFAULT_QUERIES, DEFAULT_QUERY_STRING } from './con import { ObservabilityAlertSearchBarProps } from './types'; import { buildEsQuery } from '../../utils/build_es_query'; import { AlertStatus } from '../../../common/typings'; -import { useKibana } from '../../utils/kibana_react'; const getAlertStatusQuery = (status: string): Query[] => { return ALERT_STATUS_QUERY[status] @@ -39,11 +38,10 @@ export function ObservabilityAlertSearchBar({ kuery, rangeFrom, rangeTo, - services: { AlertsSearchBar, timeFilterService, useToasts }, + services: { AlertsSearchBar, timeFilterService, useToasts, uiSettings }, status, }: ObservabilityAlertSearchBarProps) { const toasts = useToasts(); - const { uiSettings } = useKibana().services; const onAlertStatusChange = useCallback( (alertStatus: AlertStatus) => { diff --git a/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar_with_url_sync.tsx b/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar_with_url_sync.tsx index 91a3453c23ea0..0ce6be6003517 100644 --- a/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar_with_url_sync.tsx +++ b/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar_with_url_sync.tsx @@ -26,13 +26,14 @@ function AlertSearchbarWithUrlSync(props: AlertSearchBarWithUrlSyncProps) { }, }, triggersActionsUi: { getAlertsSearchBar: AlertsSearchBar }, + uiSettings, } = useKibana().services; return ( ); } diff --git a/x-pack/plugins/observability/public/components/alert_search_bar/types.ts b/x-pack/plugins/observability/public/components/alert_search_bar/types.ts index 426aea00886cf..a527f5deca40c 100644 --- a/x-pack/plugins/observability/public/components/alert_search_bar/types.ts +++ b/x-pack/plugins/observability/public/components/alert_search_bar/types.ts @@ -10,8 +10,8 @@ import { ToastsStart } from '@kbn/core-notifications-browser'; import { TimefilterContract } from '@kbn/data-plugin/public'; import { AlertsSearchBarProps } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alerts_search_bar'; import { BoolQuery, Query } from '@kbn/es-query'; +import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; import { AlertStatus } from '../../../common/typings'; - export interface AlertStatusFilterProps { status: AlertStatus; onChange: (id: AlertStatus) => void; @@ -37,6 +37,7 @@ export interface Services { timeFilterService: TimefilterContract; AlertsSearchBar: (props: AlertsSearchBarProps) => ReactElement; useToasts: () => ToastsStart; + uiSettings: IUiSettingsClient; } export interface ObservabilityAlertSearchBarProps diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts.tsx index daf02e9f6fd09..903a76328bdd4 100644 --- a/x-pack/plugins/observability/public/pages/alerts/alerts.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/alerts.tsx @@ -63,6 +63,7 @@ function InternalAlertsPage() { getAlertsStateTable: AlertsStateTable, getAlertSummaryWidget: AlertSummaryWidget, }, + uiSettings, } = kibanaServices; const { ObservabilityPageTemplate } = usePluginContext(); const alertSearchBarStateProps = useAlertSearchBarStateContainer(ALERTS_URL_STORAGE_KEY, { @@ -198,7 +199,7 @@ function InternalAlertsPage() { {...alertSearchBarStateProps} appName={ALERTS_SEARCH_BAR_ID} onEsQueryChange={setEsQuery} - services={{ timeFilterService, AlertsSearchBar, useToasts }} + services={{ timeFilterService, AlertsSearchBar, useToasts, uiSettings }} /> diff --git a/x-pack/plugins/observability/tsconfig.json b/x-pack/plugins/observability/tsconfig.json index cf3402a90c888..ba9ac59725adc 100644 --- a/x-pack/plugins/observability/tsconfig.json +++ b/x-pack/plugins/observability/tsconfig.json @@ -101,7 +101,8 @@ "@kbn/task-manager-plugin", "@kbn/core-elasticsearch-client-server-mocks", "@kbn/ingest-pipelines-plugin", - "@kbn/core-saved-objects-api-server-mocks" + "@kbn/core-saved-objects-api-server-mocks", + "@kbn/core-ui-settings-browser-mocks" ], "exclude": [ "target/**/*" From 51d708e1c0b5f001076c217e7c5e8eeaf88544ae Mon Sep 17 00:00:00 2001 From: Julia Bardi <90178898+juliaElastic@users.noreply.github.com> Date: Thu, 4 Jan 2024 12:30:52 +0100 Subject: [PATCH 006/100] [Fleet] allow agent upgrade when agent is on latest version (#174158) ## Summary Closes https://github.com/elastic/ingest-dev/issues/2726 Allow upgrade with typing in agent version when agent is on latest version according to the version list. This is an escape hatch if the version list does not contain the latest version. To verify: - enroll an agent locally or in a vm with latest published version 8.11.3 - check that Upgrade agent action is not disabled in agent list (single and bulk action) and agent details. - when opening the upgrade agent modal, the combo box should allow typing in any version - the upgrade available badge is hidden when the agent is on the latest version in the list image image image ### 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 --- .../services/is_agent_upgradeable.test.ts | 102 +++++----- .../common/services/is_agent_upgradeable.ts | 63 +++--- .../components/action_menu.test.tsx | 4 +- .../components/actions_menu.tsx | 5 +- .../agent_details/agent_details_overview.tsx | 18 +- .../components/agent_list_table.tsx | 23 +-- .../components/agent_upgrade_status.test.tsx | 191 +++++++++++------- .../components/agent_upgrade_status.tsx | 30 ++- .../components/table_row_actions.test.tsx | 4 +- .../components/table_row_actions.tsx | 5 +- .../agent_upgrade_modal/index.test.tsx | 24 ++- .../components/agent_upgrade_modal/index.tsx | 64 +++--- .../server/routes/agent/upgrade_handler.ts | 4 +- .../fleet/server/services/agents/crud.test.ts | 2 +- .../fleet/server/services/agents/crud.ts | 6 +- .../services/agents/upgrade_action_runner.ts | 4 +- .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 19 files changed, 299 insertions(+), 253 deletions(-) diff --git a/x-pack/plugins/fleet/common/services/is_agent_upgradeable.test.ts b/x-pack/plugins/fleet/common/services/is_agent_upgradeable.test.ts index dbc5b5515b6bb..22ac8e80949ea 100644 --- a/x-pack/plugins/fleet/common/services/is_agent_upgradeable.test.ts +++ b/x-pack/plugins/fleet/common/services/is_agent_upgradeable.test.ts @@ -12,6 +12,8 @@ import { isAgentUpgradeable, isAgentUpgrading, getNotUpgradeableMessage, + isAgentUpgradeAvailable, + isAgentUpgradeableToVersion, } from './is_agent_upgradeable'; const getAgent = ({ @@ -116,77 +118,51 @@ const getAgent = ({ } return agent; }; -describe('Fleet - isAgentUpgradeable', () => { +describe('Fleet - isAgentUpgradeAvailable', () => { it('returns false if agent reports not upgradeable with agent version < latest agent version', () => { - expect(isAgentUpgradeable(getAgent({ version: '7.9.0' }), '8.0.0')).toBe(false); + expect(isAgentUpgradeAvailable(getAgent({ version: '7.9.0' }), '8.0.0')).toBe(false); }); it('returns false if agent reports not upgradeable with agent version > latest agent version', () => { - expect(isAgentUpgradeable(getAgent({ version: '8.0.0' }), '7.9.0')).toBe(false); + expect(isAgentUpgradeAvailable(getAgent({ version: '8.0.0' }), '7.9.0')).toBe(false); }); it('returns false if agent reports not upgradeable with agent version === latest agent version', () => { - expect(isAgentUpgradeable(getAgent({ version: '8.0.0' }), '8.0.0')).toBe(false); + expect(isAgentUpgradeAvailable(getAgent({ version: '8.0.0' }), '8.0.0')).toBe(false); }); it('returns false if agent reports upgradeable, with agent version === latest agent version', () => { - expect(isAgentUpgradeable(getAgent({ version: '8.0.0', upgradeable: true }), '8.0.0')).toBe( - false - ); - }); - it('returns false if agent reports upgradeable, with agent version > latest agent version', () => { - expect(isAgentUpgradeable(getAgent({ version: '8.0.0', upgradeable: true }), '7.9.0')).toBe( - false - ); - }); - it('returns false if agent reports upgradeable, but agent is unenrolling', () => { expect( - isAgentUpgradeable( - getAgent({ version: '7.9.0', upgradeable: true, unenrolling: true }), - '8.0.0' - ) + isAgentUpgradeAvailable(getAgent({ version: '8.0.0', upgradeable: true }), '8.0.0') ).toBe(false); }); - it('returns false if agent reports upgradeable, but agent is unenrolled', () => { + it('returns false if agent reports upgradeable, with agent version > latest agent version', () => { expect( - isAgentUpgradeable( - getAgent({ version: '7.9.0', upgradeable: true, unenrolled: true }), - '8.0.0' - ) + isAgentUpgradeAvailable(getAgent({ version: '8.0.0', upgradeable: true }), '7.9.0') ).toBe(false); }); it('returns true if agent reports upgradeable, with agent version < latest agent version', () => { - expect(isAgentUpgradeable(getAgent({ version: '7.9.0', upgradeable: true }), '8.0.0')).toBe( - true - ); + expect( + isAgentUpgradeAvailable(getAgent({ version: '7.9.0', upgradeable: true }), '8.0.0') + ).toBe(true); }); it('returns false if agent reports upgradeable, with agent snapshot version === latest agent version', () => { expect( - isAgentUpgradeable(getAgent({ version: '7.9.0-SNAPSHOT', upgradeable: true }), '7.9.0') + isAgentUpgradeAvailable(getAgent({ version: '7.9.0-SNAPSHOT', upgradeable: true }), '7.9.0') ).toBe(false); }); - it('returns true if agent reports upgradeable, with upgrade to agent snapshot version newer than latest agent version', () => { - expect( - isAgentUpgradeable( - getAgent({ version: '8.10.2', upgradeable: true }), - '8.10.2', - '8.11.0-SNAPSHOT' - ) - ).toBe(true); - }); - it('returns false if agent reports upgradeable, with target version < current agent version ', () => { +}); +describe('Fleet - isAgentUpgradeable', () => { + it('returns false if agent reports upgradeable, but agent is unenrolling', () => { expect( - isAgentUpgradeable(getAgent({ version: '7.9.0', upgradeable: true }), '8.0.0', '7.8.0') + isAgentUpgradeable(getAgent({ version: '7.9.0', upgradeable: true, unenrolling: true })) ).toBe(false); }); - it('returns false if agent reports upgradeable, with target version == current agent version ', () => { + it('returns false if agent reports upgradeable, but agent is unenrolled', () => { expect( - isAgentUpgradeable(getAgent({ version: '7.9.0', upgradeable: true }), '8.0.0', '7.9.0') + isAgentUpgradeable(getAgent({ version: '7.9.0', upgradeable: true, unenrolled: true })) ).toBe(false); }); it('returns false if agent with no upgrade details reports upgradeable, but is already upgrading', () => { expect( - isAgentUpgradeable( - getAgent({ version: '7.9.0', upgradeable: true, upgrading: true }), - '8.0.0' - ) + isAgentUpgradeable(getAgent({ version: '7.9.0', upgradeable: true, upgrading: true })) ).toBe(false); }); it('returns false if agent reports upgradeable, but has an upgrade status other than failed', () => { @@ -200,8 +176,7 @@ describe('Fleet - isAgentUpgradeable', () => { action_id: 'XXX', state: 'UPG_REQUESTED', }, - }), - '8.0.0' + }) ) ).toBe(false); }); @@ -219,27 +194,40 @@ describe('Fleet - isAgentUpgradeable', () => { error_msg: 'Upgrade timed out', }, }, - }), - '8.0.0' + }) ) ).toBe(true); }); it('returns false if the agent reports upgradeable but was upgraded less than 10 minutes ago', () => { expect( - isAgentUpgradeable( - getAgent({ version: '7.9.0', upgradeable: true, minutesSinceUpgrade: 9 }), - '8.0.0' - ) + isAgentUpgradeable(getAgent({ version: '7.9.0', upgradeable: true, minutesSinceUpgrade: 9 })) ).toBe(false); }); it('returns true if agent reports upgradeable and was upgraded more than 10 minutes ago', () => { expect( - isAgentUpgradeable( - getAgent({ version: '7.9.0', upgradeable: true, minutesSinceUpgrade: 11 }), - '8.0.0' + isAgentUpgradeable(getAgent({ version: '7.9.0', upgradeable: true, minutesSinceUpgrade: 11 })) + ).toBe(true); + }); +}); +describe('Fleet - isAgentUpgradeableToVersion', () => { + it('returns true if agent reports upgradeable, with upgrade to agent snapshot version newer than latest agent version', () => { + expect( + isAgentUpgradeableToVersion( + getAgent({ version: '8.10.2', upgradeable: true }), + '8.11.0-SNAPSHOT' ) ).toBe(true); }); + it('returns false if agent reports upgradeable, with target version < current agent version ', () => { + expect( + isAgentUpgradeableToVersion(getAgent({ version: '7.9.0', upgradeable: true }), '7.8.0') + ).toBe(false); + }); + it('returns false if agent reports upgradeable, with target version == current agent version ', () => { + expect( + isAgentUpgradeableToVersion(getAgent({ version: '7.9.0', upgradeable: true }), '7.9.0') + ).toBe(false); + }); }); describe('Fleet - getNotUpgradeableMessage', () => { @@ -264,7 +252,7 @@ describe('Fleet - getNotUpgradeableMessage', () => { it('if agent reports upgradeable, with agent version === latest agent version', () => { expect( getNotUpgradeableMessage(getAgent({ version: '8.0.0', upgradeable: true }), '8.0.0') - ).toBe('agent is already running on the latest available version.'); + ).toBe(undefined); }); it('if agent reports upgradeable, with agent version > latest agent version', () => { @@ -300,7 +288,7 @@ describe('Fleet - getNotUpgradeableMessage', () => { it('if agent reports upgradeable, with agent snapshot version === latest agent version', () => { expect( getNotUpgradeableMessage(getAgent({ version: '7.9.0-SNAPSHOT', upgradeable: true }), '7.9.0') - ).toBe('agent is already running on the latest available version.'); + ).toBe(undefined); }); it('it does not return message if agent reports upgradeable, with upgrade to agent snapshot version newer than latest agent version', () => { diff --git a/x-pack/plugins/fleet/common/services/is_agent_upgradeable.ts b/x-pack/plugins/fleet/common/services/is_agent_upgradeable.ts index d36010aa13b98..8d2108ee83ef0 100644 --- a/x-pack/plugins/fleet/common/services/is_agent_upgradeable.ts +++ b/x-pack/plugins/fleet/common/services/is_agent_upgradeable.ts @@ -29,21 +29,20 @@ export const LATEST_VERSION_NOT_VALID_ERROR = 'latest version is not valid.'; export const AGENT_ALREADY_ON_LATEST_ERROR = `agent is already running on the latest available version.`; export const AGENT_ON_GREATER_VERSION_ERROR = `agent is running on a version greater than the latest available version.`; -export function isAgentUpgradeable( - agent: Agent, - latestAgentVersion: string, - versionToUpgrade?: string -) { - let agentVersion: string; - if (typeof agent?.local_metadata?.elastic?.agent?.version === 'string') { - agentVersion = agent.local_metadata.elastic.agent.version; - } else { - return false; - } +export function isAgentUpgradeAvailable(agent: Agent, latestAgentVersion?: string) { + return ( + latestAgentVersion && + isAgentUpgradeable(agent) && + agent?.local_metadata?.elastic?.agent?.version && + isAgentVersionLessThanLatest(agent.local_metadata.elastic.agent.version, latestAgentVersion) + ); +} + +export function isAgentUpgradeable(agent: Agent) { if (agent.unenrollment_started_at || agent.unenrolled_at) { return false; } - if (!agent.local_metadata.elastic.agent.upgradeable) { + if (!agent.local_metadata?.elastic?.agent?.upgradeable) { return false; } if (isAgentUpgrading(agent)) { @@ -52,12 +51,34 @@ export function isAgentUpgradeable( if (getRecentUpgradeInfoForAgent(agent).hasBeenUpgradedRecently) { return false; } - if (versionToUpgrade !== undefined) { - return isNotDowngrade(agentVersion, versionToUpgrade); + return true; +} + +export function isAgentUpgradeableToVersion(agent: Agent, versionToUpgrade?: string) { + const isAgentUpgradeableCheck = isAgentUpgradeable(agent); + if (!isAgentUpgradeableCheck) return false; + let agentVersion: string; + if (typeof agent?.local_metadata?.elastic?.agent?.version === 'string') { + agentVersion = agent.local_metadata.elastic.agent.version; + } else { + return false; + } + if (!versionToUpgrade) { + return false; } - return isAgentVersionLessThanLatest(agentVersion, latestAgentVersion); + return isNotDowngrade(agentVersion, versionToUpgrade); } +export const isAgentVersionLessThanLatest = (agentVersion: string, latestAgentVersion: string) => { + // make sure versions are only the number before comparison + const agentVersionNumber = semverCoerce(agentVersion); + if (!agentVersionNumber) throw new Error(`${INVALID_VERSION_ERROR}`); + const latestAgentVersionNumber = semverCoerce(latestAgentVersion); + if (!latestAgentVersionNumber) throw new Error(`${LATEST_VERSION_NOT_VALID_ERROR}`); + + return semverLt(agentVersionNumber, latestAgentVersionNumber); +}; + // Based on the previous, returns a detailed message explaining why the agent is not upgradeable export const getNotUpgradeableMessage = ( agent: Agent, @@ -105,24 +126,12 @@ export const getNotUpgradeableMessage = ( const latestAgentVersionNumber = semverCoerce(latestAgentVersion); if (!latestAgentVersionNumber) return LATEST_VERSION_NOT_VALID_ERROR; - if (semverEq(agentVersionNumber, latestAgentVersionNumber)) return AGENT_ALREADY_ON_LATEST_ERROR; - if (semverGt(agentVersionNumber, latestAgentVersionNumber)) return AGENT_ON_GREATER_VERSION_ERROR; // in all the other cases, the agent is upgradeable; don't return any message. return undefined; }; -const isAgentVersionLessThanLatest = (agentVersion: string, latestAgentVersion: string) => { - // make sure versions are only the number before comparison - const agentVersionNumber = semverCoerce(agentVersion); - if (!agentVersionNumber) throw new Error(`${INVALID_VERSION_ERROR}`); - const latestAgentVersionNumber = semverCoerce(latestAgentVersion); - if (!latestAgentVersionNumber) throw new Error(`${LATEST_VERSION_NOT_VALID_ERROR}`); - - return semverLt(agentVersionNumber, latestAgentVersionNumber); -}; - const isNotDowngrade = (agentVersion: string, versionToUpgrade: string) => { const agentVersionNumber = semverCoerce(agentVersion); if (!agentVersionNumber) throw new Error(`${INVALID_VERSION_ERROR}`); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx index 2d39700da5caa..17004f5eef7cf 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx @@ -238,7 +238,7 @@ describe('AgentDetailsActionMenu', () => { expect(res).toBeEnabled(); }); - it('should render a disabled action button if agent version is latest', async () => { + it('should render an enabled action button if agent version is latest', async () => { const res = renderAndGetUpgradeButton({ agent: { active: true, @@ -249,7 +249,7 @@ describe('AgentDetailsActionMenu', () => { }); expect(res).not.toBe(null); - expect(res).not.toBeEnabled(); + expect(res).toBeEnabled(); }); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx index d2426dbac8ca5..a9d58c0c9d11e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx @@ -13,7 +13,7 @@ import { isAgentRequestDiagnosticsSupported } from '../../../../../../../common/ import { isStuckInUpdating } from '../../../../../../../common/services/agent_status'; import type { Agent, AgentPolicy } from '../../../../types'; -import { useAgentVersion, useAuthz } from '../../../../hooks'; +import { useAuthz } from '../../../../hooks'; import { ContextMenuActions } from '../../../../components'; import { AgentUnenrollAgentModal, @@ -34,7 +34,6 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{ onCancelReassign?: () => void; }> = memo(({ agent, assignFlyoutOpenByDefault = false, onCancelReassign, agentPolicy }) => { const hasFleetAllPrivileges = useAuthz().fleet.all; - const latestAgentVersion = useAgentVersion(); const refreshAgent = useAgentRefresh(); const [isReassignFlyoutOpen, setIsReassignFlyoutOpen] = useState(assignFlyoutOpenByDefault); const [isUnenrollModalOpen, setIsUnenrollModalOpen] = useState(false); @@ -102,7 +101,7 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{ , { setIsUpgradeModalOpen(true); }} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_overview.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_overview.tsx index 45d5ead9909ee..44c4138b16650 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_overview.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_overview.tsx @@ -23,11 +23,7 @@ import { FormattedMessage, FormattedRelative } from '@kbn/i18n-react'; import type { Agent, AgentPolicy } from '../../../../../types'; import { useAgentVersion } from '../../../../../hooks'; -import { - ExperimentalFeaturesService, - isAgentUpgradeable, - getNotUpgradeableMessage, -} from '../../../../../services'; +import { ExperimentalFeaturesService, isAgentUpgradeable } from '../../../../../services'; import { AgentPolicySummaryLine } from '../../../../../components'; import { AgentHealth } from '../../../components'; import { Tags } from '../../../components/tags'; @@ -181,16 +177,10 @@ export const AgentDetailsOverviewSection: React.FunctionComponent<{ diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_list_table.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_list_table.tsx index d555c163c0fc0..94414965183f0 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_list_table.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_list_table.tsx @@ -31,8 +31,6 @@ import { Tags } from '../../components/tags'; import type { AgentMetrics } from '../../../../../../../common/types'; import { formatAgentCPU, formatAgentMemory } from '../../services/agent_metrics'; -import { getNotUpgradeableMessage } from '../../../../../../../common/services/is_agent_upgradeable'; - import { AgentUpgradeStatus } from './agent_upgrade_status'; import { EmptyPrompt } from './empty_prompt'; @@ -295,17 +293,9 @@ export const AgentListTable: React.FC = (props: Props) => { @@ -337,12 +327,7 @@ export const AgentListTable: React.FC = (props: Props) => { items={ totalAgents ? showUpgradeable - ? agents.filter( - (agent) => - isAgentSelectable(agent) && - latestAgentVersion && - isAgentUpgradeable(agent, latestAgentVersion) - ) + ? agents.filter((agent) => isAgentSelectable(agent) && isAgentUpgradeable(agent)) : agents : [] } diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.test.tsx index 1155176bf7915..336955289e2d6 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.test.tsx @@ -131,10 +131,12 @@ describe('AgentUpgradeStatus', () => { describe('with agent upgrade details', () => { it('should render UPG_REQUESTED state correctly', async () => { const results = render({ - agentUpgradeDetails: { - target_version: 'XXX', - action_id: 'xxx', - state: 'UPG_REQUESTED', + agent: { + upgrade_details: { + target_version: 'XXX', + action_id: 'xxx', + state: 'UPG_REQUESTED', + }, }, }); @@ -144,12 +146,14 @@ describe('AgentUpgradeStatus', () => { it('should render UPG_SCHEDULED state correctly', async () => { const results = render({ - agentUpgradeDetails: { - target_version: 'XXX', - action_id: 'xxx', - state: 'UPG_SCHEDULED', - metadata: { - scheduled_at: getDateString(200), + agent: { + upgrade_details: { + target_version: 'XXX', + action_id: 'xxx', + state: 'UPG_SCHEDULED', + metadata: { + scheduled_at: getDateString(200), + }, }, }, }); @@ -163,12 +167,14 @@ describe('AgentUpgradeStatus', () => { it('should render UPG_DOWNLOADING state correctly', async () => { const results = render({ - agentUpgradeDetails: { - target_version: 'XXX', - action_id: 'xxx', - state: 'UPG_DOWNLOADING', - metadata: { - download_percent: 16.4, + agent: { + upgrade_details: { + target_version: 'XXX', + action_id: 'xxx', + state: 'UPG_DOWNLOADING', + metadata: { + download_percent: 16.4, + }, }, }, }); @@ -179,14 +185,16 @@ describe('AgentUpgradeStatus', () => { it('should render UPG_DOWNLOADING with a warning if agent has a retry_message and retry_until', async () => { const results = render({ - agentUpgradeDetails: { - target_version: 'XXX', - action_id: 'xxx', - state: 'UPG_DOWNLOADING', - metadata: { - download_percent: 16.4, - retry_error_msg: 'unable to download', - retry_until: `${moment().add(10, 'minutes').toISOString()}`, + agent: { + upgrade_details: { + target_version: 'XXX', + action_id: 'xxx', + state: 'UPG_DOWNLOADING', + metadata: { + download_percent: 16.4, + retry_error_msg: 'unable to download', + retry_until: `${moment().add(10, 'minutes').toISOString()}`, + }, }, }, }); @@ -202,14 +210,16 @@ describe('AgentUpgradeStatus', () => { it('should not render retry_until if the remaining time is negative', async () => { const results = render({ - agentUpgradeDetails: { - target_version: 'XXX', - action_id: 'xxx', - state: 'UPG_DOWNLOADING', - metadata: { - download_percent: 16.4, - retry_error_msg: 'unable to download', - retry_until: `${moment().subtract(10, 'minutes').toISOString()}`, + agent: { + upgrade_details: { + target_version: 'XXX', + action_id: 'xxx', + state: 'UPG_DOWNLOADING', + metadata: { + download_percent: 16.4, + retry_error_msg: 'unable to download', + retry_until: `${moment().subtract(10, 'minutes').toISOString()}`, + }, }, }, }); @@ -225,13 +235,15 @@ describe('AgentUpgradeStatus', () => { it('should render UPG_DOWNLOADING with a warning if agent has a retry_message', async () => { const results = render({ - agentUpgradeDetails: { - target_version: 'XXX', - action_id: 'xxx', - state: 'UPG_DOWNLOADING', - metadata: { - download_percent: 16.4, - retry_error_msg: 'unable to download', + agent: { + upgrade_details: { + target_version: 'XXX', + action_id: 'xxx', + state: 'UPG_DOWNLOADING', + metadata: { + download_percent: 16.4, + retry_error_msg: 'unable to download', + }, }, }, }); @@ -242,10 +254,12 @@ describe('AgentUpgradeStatus', () => { it('should render UPG_EXTRACTING state correctly', async () => { const results = render({ - agentUpgradeDetails: { - target_version: 'XXX', - action_id: 'xxx', - state: 'UPG_EXTRACTING', + agent: { + upgrade_details: { + target_version: 'XXX', + action_id: 'xxx', + state: 'UPG_EXTRACTING', + }, }, }); @@ -255,10 +269,12 @@ describe('AgentUpgradeStatus', () => { it('should render UPG_REPLACING state correctly', async () => { const results = render({ - agentUpgradeDetails: { - target_version: 'XXX', - action_id: 'xxx', - state: 'UPG_REPLACING', + agent: { + upgrade_details: { + target_version: 'XXX', + action_id: 'xxx', + state: 'UPG_REPLACING', + }, }, }); @@ -268,10 +284,12 @@ describe('AgentUpgradeStatus', () => { it('should render UPG_RESTARTING state correctly', async () => { const results = render({ - agentUpgradeDetails: { - target_version: 'XXX', - action_id: 'xxx', - state: 'UPG_RESTARTING', + agent: { + upgrade_details: { + target_version: 'XXX', + action_id: 'xxx', + state: 'UPG_RESTARTING', + }, }, }); @@ -281,10 +299,12 @@ describe('AgentUpgradeStatus', () => { it('should render UPG_WATCHING state correctly', async () => { const results = render({ - agentUpgradeDetails: { - target_version: 'XXX', - action_id: 'xxx', - state: 'UPG_WATCHING', + agent: { + upgrade_details: { + target_version: 'XXX', + action_id: 'xxx', + state: 'UPG_WATCHING', + }, }, }); @@ -294,10 +314,12 @@ describe('AgentUpgradeStatus', () => { it('should render UPG_ROLLBACK state correctly', async () => { const results = render({ - agentUpgradeDetails: { - target_version: 'XXX', - action_id: 'xxx', - state: 'UPG_ROLLBACK', + agent: { + upgrade_details: { + target_version: 'XXX', + action_id: 'xxx', + state: 'UPG_ROLLBACK', + }, }, }); @@ -307,13 +329,15 @@ describe('AgentUpgradeStatus', () => { it('should render UPG_FAILED state correctly', async () => { const results = render({ - agentUpgradeDetails: { - target_version: 'XXX', - action_id: 'xxx', - state: 'UPG_FAILED', - metadata: { - failed_state: 'UPG_DOWNLOADING', - error_msg: 'Something went wrong', + agent: { + upgrade_details: { + target_version: 'XXX', + action_id: 'xxx', + state: 'UPG_FAILED', + metadata: { + failed_state: 'UPG_DOWNLOADING', + error_msg: 'Something went wrong', + }, }, }, }); @@ -327,6 +351,8 @@ describe('AgentUpgradeStatus', () => { it('should render a badge with no tooltip if the agent is upgradable', () => { const results = render({ isAgentUpgradable: true, + agent: { local_metadata: { elastic: { agent: { version: '8.11.0', upgradeable: true } } } }, + latestAgentVersion: '8.12.0', }); expectNoUpgradeStatusBadges(results); @@ -334,10 +360,31 @@ describe('AgentUpgradeStatus', () => { expect(results.queryAllByText('Info')).toEqual([]); }); + it('should not render a badge if the agent is on latest version', () => { + const results = render({ + isAgentUpgradable: true, + agent: { local_metadata: { elastic: { agent: { version: '8.12.0', upgradeable: true } } } }, + latestAgentVersion: '8.12.0', + }); + + expectNoUpgradeStatusBadges(results); + expect(results.queryByText('Upgrade available')).not.toBeInTheDocument(); + }); + + it('should not render a badge if the agent is version is newer than latest version', () => { + const results = render({ + isAgentUpgradable: true, + agent: { local_metadata: { elastic: { agent: { version: '8.12.0', upgradeable: true } } } }, + latestAgentVersion: '8.11.0', + }); + + expectNoUpgradeStatusBadges(results); + expect(results.queryByText('Upgrade available')).not.toBeInTheDocument(); + }); + it('should render an icon with tooltip if the agent is upgrading', async () => { const results = render({ - agentUpgradeStartedAt: '2023-10-03T14:34:12Z', - agentUpgradedAt: null, + agent: { upgrade_started_at: '2023-10-03T14:34:12Z', upgraded_at: null }, }); expectNoUpgradeStatusBadges(results); @@ -351,8 +398,12 @@ describe('AgentUpgradeStatus', () => { it('should not render anything if the agent is neither upgrading nor upgradable', () => { const results = render({ - agentUpgradeStartedAt: null, - agentUpgradedAt: '2023-10-03T14:34:12Z', + agent: { + upgrade_started_at: null, + upgraded_at: '2023-10-03T14:34:12Z', + local_metadata: { elastic: { agent: { version: '8.12.0', upgradeable: true } } }, + }, + latestAgentVersion: '8.12.0', }); expectNoUpgradeStatusBadges(results); expect( diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.tsx index cf3ad42292533..dceb1de73527b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.tsx @@ -10,7 +10,12 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui'; import moment from 'moment'; +import type { Agent } from '../../../../types'; import type { AgentUpgradeDetails } from '../../../../../../../common/types'; +import { + getNotUpgradeableMessage, + isAgentUpgradeAvailable, +} from '../../../../../../../common/services'; /** * Returns a user-friendly string for the estimated remaining time until the upgrade is scheduled. @@ -267,25 +272,18 @@ function getStatusComponents(agentUpgradeDetails?: AgentUpgradeDetails) { export const AgentUpgradeStatus: React.FC<{ isAgentUpgradable: boolean; - agentUpgradeStartedAt?: string | null; - agentUpgradedAt?: string | null; - agentUpgradeDetails?: AgentUpgradeDetails; - notUpgradeableMessage?: string | null; -}> = ({ - isAgentUpgradable, - agentUpgradeStartedAt, - agentUpgradedAt, - agentUpgradeDetails, - notUpgradeableMessage, -}) => { + agent: Agent; + latestAgentVersion?: string; +}> = ({ isAgentUpgradable, agent, latestAgentVersion }) => { const isAgentUpgrading = useMemo( - () => agentUpgradeStartedAt && !agentUpgradedAt, - [agentUpgradeStartedAt, agentUpgradedAt] + () => agent.upgrade_started_at && !agent.upgraded_at, + [agent.upgrade_started_at, agent.upgraded_at] ); - const status = useMemo(() => getStatusComponents(agentUpgradeDetails), [agentUpgradeDetails]); + const status = useMemo(() => getStatusComponents(agent.upgrade_details), [agent.upgrade_details]); const minVersion = '8.12'; + const notUpgradeableMessage = getNotUpgradeableMessage(agent, latestAgentVersion); - if (isAgentUpgradable) { + if (isAgentUpgradable && isAgentUpgradeAvailable(agent, latestAgentVersion)) { return ( {status.Badge} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx index 4e8d25f313ea5..fd3f130851d9f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx @@ -216,7 +216,7 @@ describe('TableRowActions', () => { expect(res).toBeEnabled(); }); - it('should render a disabled action button if agent version is latest', async () => { + it('should render an enabled action button if agent version is latest', async () => { const res = renderAndGetUpgradeButton({ agent: { active: true, @@ -229,7 +229,7 @@ describe('TableRowActions', () => { }); expect(res).not.toBe(null); - expect(res).not.toBeEnabled(); + expect(res).toBeEnabled(); }); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.tsx index ba2efb1d86f81..8e27cd281d946 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.tsx @@ -14,7 +14,7 @@ import { isAgentRequestDiagnosticsSupported } from '../../../../../../../common/ import { isStuckInUpdating } from '../../../../../../../common/services/agent_status'; import type { Agent, AgentPolicy } from '../../../../types'; -import { useAuthz, useLink, useAgentVersion } from '../../../../hooks'; +import { useAuthz, useLink } from '../../../../hooks'; import { ContextMenuActions } from '../../../../components'; import { isAgentUpgradeable } from '../../../../services'; import { ExperimentalFeaturesService } from '../../../../services'; @@ -42,7 +42,6 @@ export const TableRowActions: React.FunctionComponent<{ const hasFleetAllPrivileges = useAuthz().fleet.all; const isUnenrolling = agent.status === 'unenrolling'; - const latestAgentVersion = useAgentVersion(); const [isMenuOpen, setIsMenuOpen] = useState(false); const { diagnosticFileUploadEnabled, agentTamperProtectionEnabled } = ExperimentalFeaturesService.get(); @@ -107,7 +106,7 @@ export const TableRowActions: React.FunctionComponent<{ { onUpgradeClick(); }} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.test.tsx index 17e415691a826..3073420f4dc58 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.test.tsx @@ -90,8 +90,8 @@ describe('AgentUpgradeAgentModal', () => { agentCount: 30, }); - const el = utils.getByTestId('agentUpgradeModal.VersionCombobox'); await waitFor(() => { + const el = utils.getByTestId('agentUpgradeModal.VersionCombobox'); expect(el.classList.contains('euiComboBox-isDisabled')).toBe(false); }); }); @@ -102,14 +102,30 @@ describe('AgentUpgradeAgentModal', () => { agentCount: 1, }); - const container = utils.getByTestId('agentUpgradeModal.VersionCombobox'); - const input = within(container).getByRole('combobox'); - await waitFor(() => { + const container = utils.getByTestId('agentUpgradeModal.VersionCombobox'); + const input = within(container).getByRole('combobox'); expect(input?.value).toEqual('8.10.2'); }); }); + it('should display the custom version text input if no versions', async () => { + const { utils } = renderAgentUpgradeAgentModal({ + agents: [ + { + id: 'agent1', + local_metadata: { host: 'abc', elastic: { agent: { version: '8.12.0' } } }, + }, + ] as any, + agentCount: 1, + }); + + await waitFor(() => { + const input = utils.getByTestId('agentUpgradeModal.VersionInput'); + expect(input?.textContent).toEqual(''); + }); + }); + it('should display available version options', async () => { mockSendGetAgentsAvailableVersions.mockClear(); mockSendGetAgentsAvailableVersions.mockResolvedValue({ diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx index 28bb86fdb5382..aeea51987f43c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx @@ -19,6 +19,7 @@ import { EuiFlexItem, EuiCallOut, EuiDatePicker, + EuiFieldText, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -49,8 +50,8 @@ import { import { sendGetAgentsAvailableVersions } from '../../../../hooks'; import { - isAgentUpgradeable, getNotUpgradeableMessage, + isAgentUpgradeableToVersion, } from '../../../../../../../common/services/is_agent_upgradeable'; import { @@ -206,6 +207,8 @@ export const AgentUpgradeAgentModal: React.FunctionComponent { @@ -243,7 +246,7 @@ export const AgentUpgradeAgentModal: React.FunctionComponent ) : isSingleAgent ? ( - !isAgentUpgradeable(agents[0], latestAgentVersion || '', selectedVersion[0].value) ? ( + !isAgentUpgradeableToVersion(agents[0], selectedVersion[0].value) ? ( - >) => { - if (!selected.length) { - return; + {noVersions ? ( + { + const newValue = e.target.value; + setSelectedVersionStr(newValue); + setSelectedVersion([{ label: newValue, value: newValue }]); + }} + /> + ) : ( + >) => { + if (!selected.length) { + return; + } + setSelectedVersion(selected); + }} + onCreateOption={ + config?.internal?.onlyAllowAgentUpgradeToKnownVersions ? undefined : onCreateOption } - setSelectedVersion(selected); - }} - onCreateOption={ - config?.internal?.onlyAllowAgentUpgradeToKnownVersions ? undefined : onCreateOption - } - customOptionText="Use custom agent version {searchValue} (not recommended)" - /> + customOptionText="Use custom agent version {searchValue} (not recommended)" + /> + )} {!isSingleAgent && Array.isArray(agents) && diff --git a/x-pack/plugins/fleet/server/routes/agent/upgrade_handler.ts b/x-pack/plugins/fleet/server/routes/agent/upgrade_handler.ts index 3b1cd89ff1364..471264fbe1fd0 100644 --- a/x-pack/plugins/fleet/server/routes/agent/upgrade_handler.ts +++ b/x-pack/plugins/fleet/server/routes/agent/upgrade_handler.ts @@ -22,10 +22,10 @@ import { appContextService } from '../../services'; import { defaultFleetErrorHandler, AgentRequestInvalidError } from '../../errors'; import { getRecentUpgradeInfoForAgent, - isAgentUpgradeable, AGENT_UPGRADE_COOLDOWN_IN_MIN, isAgentUpgrading, getNotUpgradeableMessage, + isAgentUpgradeableToVersion, } from '../../../common/services'; import { getMaxVersion } from '../../../common/services/get_min_max_version'; import { getAgentById } from '../../services/agents'; @@ -111,7 +111,7 @@ export const postAgentUpgradeHandler: RequestHandler< }); } - if (!force && !isAgentUpgradeable(agent, latestAgentVersion, version)) { + if (!force && !isAgentUpgradeableToVersion(agent, version)) { return response.customError({ statusCode: 400, body: { diff --git a/x-pack/plugins/fleet/server/services/agents/crud.test.ts b/x-pack/plugins/fleet/server/services/agents/crud.test.ts index d8d65a695d3eb..93dde0737accc 100644 --- a/x-pack/plugins/fleet/server/services/agents/crud.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/crud.test.ts @@ -25,7 +25,7 @@ import { jest.mock('../audit_logging'); jest.mock('../../../common/services/is_agent_upgradeable', () => ({ - isAgentUpgradeable: jest.fn().mockImplementation((agent: Agent) => agent.id.includes('up')), + isAgentUpgradeAvailable: jest.fn().mockImplementation((agent: Agent) => agent.id.includes('up')), })); jest.mock('./versions', () => { return { diff --git a/x-pack/plugins/fleet/server/services/agents/crud.ts b/x-pack/plugins/fleet/server/services/agents/crud.ts index b8eb0f7d0ca14..d8e6e58f059ad 100644 --- a/x-pack/plugins/fleet/server/services/agents/crud.ts +++ b/x-pack/plugins/fleet/server/services/agents/crud.ts @@ -16,7 +16,7 @@ import type { AgentSOAttributes, Agent, ListWithKuery } from '../../types'; import { appContextService, agentPolicyService } from '..'; import type { AgentStatus, FleetServerAgent } from '../../../common/types'; import { SO_SEARCH_LIMIT } from '../../../common/constants'; -import { isAgentUpgradeable } from '../../../common/services'; +import { isAgentUpgradeAvailable } from '../../../common/services'; import { AGENTS_INDEX } from '../../constants'; import { FleetError, @@ -340,12 +340,12 @@ export async function getAgentsByKuery( const response = await queryAgents(0, SO_SEARCH_LIMIT); agents = response.hits.hits .map(searchHitToAgent) - .filter((agent) => isAgentUpgradeable(agent, latestAgentVersion)); + .filter((agent) => isAgentUpgradeAvailable(agent, latestAgentVersion)); total = agents.length; const start = (page - 1) * perPage; agents = agents.slice(start, start + perPage); } else { - agents = agents.filter((agent) => isAgentUpgradeable(agent, latestAgentVersion)); + agents = agents.filter((agent) => isAgentUpgradeAvailable(agent, latestAgentVersion)); } } diff --git a/x-pack/plugins/fleet/server/services/agents/upgrade_action_runner.ts b/x-pack/plugins/fleet/server/services/agents/upgrade_action_runner.ts index 61e3ad42c8aae..c294c972d3519 100644 --- a/x-pack/plugins/fleet/server/services/agents/upgrade_action_runner.ts +++ b/x-pack/plugins/fleet/server/services/agents/upgrade_action_runner.ts @@ -12,8 +12,8 @@ import moment from 'moment'; import { getRecentUpgradeInfoForAgent, - isAgentUpgradeable, getNotUpgradeableMessage, + isAgentUpgradeableToVersion, } from '../../../common/services'; import type { Agent } from '../../types'; @@ -88,7 +88,7 @@ export async function upgradeBatch( // - upgradeable b/c of version check const isNotAllowed = getRecentUpgradeInfoForAgent(agent).hasBeenUpgradedRecently || - (!options.force && !isAgentUpgradeable(agent, latestAgentVersion, options.version)); + (!options.force && !isAgentUpgradeableToVersion(agent, options.version)); if (isNotAllowed) { throw new FleetError( `Agent ${agent.id} is not upgradeable: ${getNotUpgradeableMessage( diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 1996568bbbb47..9942bbf4508e3 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -18076,7 +18076,6 @@ "xpack.fleet.upgradeAgents.confirmSingleButtonLabel": "Mettre à niveau l'agent", "xpack.fleet.upgradeAgents.fatalErrorNotificationTitle": "Erreur lors de la mise à niveau de {count, plural, one {l'agent} other {{count} agents} =true {tous les agents sélectionnés}}", "xpack.fleet.upgradeAgents.noMaintenanceWindowOption": "Immédiatement", - "xpack.fleet.upgradeAgents.noVersionsText": "Aucun agent sélectionné ne peut bénéficier d’une mise à niveau. Sélectionnez un ou plusieurs agents éligibles.", "xpack.fleet.upgradeAgents.restartConfirmMultipleButtonLabel": "Relancer la mise à niveau {count, plural, one {l'agent} other {{count} agents} =true {tous les agents sélectionnés}}", "xpack.fleet.upgradeAgents.restartUpgradeMultipleTitle": "Relancer la mise à niveau {updating} sur {count, plural, one {l’agent} other {{count} agents} =true {tous les agents}} bloqué lors de la mise à niveau", "xpack.fleet.upgradeAgents.restartUpgradeSingleTitle": "Relancer la mise à niveau", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 376f095421c63..d569cab16ee93 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -18089,7 +18089,6 @@ "xpack.fleet.upgradeAgents.confirmSingleButtonLabel": "エージェントをアップグレード", "xpack.fleet.upgradeAgents.fatalErrorNotificationTitle": "{count, plural, other {{count}個のエージェント} =true {すべての選択されたエージェント}}のアップグレードエラー", "xpack.fleet.upgradeAgents.noMaintenanceWindowOption": "直ちに実行", - "xpack.fleet.upgradeAgents.noVersionsText": "アップグレード対象の選択したエージェントはありません。1つ以上の対象のエージェントを選択してください。", "xpack.fleet.upgradeAgents.restartConfirmMultipleButtonLabel": "{count, plural, other {{count}個のエージェント} =true {すべての選択されたエージェント}}を再起動", "xpack.fleet.upgradeAgents.restartUpgradeMultipleTitle": "更新が停止している{count, plural, one {エージェント} other {{count}個のエージェント} =true {すべてのエージェント}}のうち{updating}でアップグレードを再開", "xpack.fleet.upgradeAgents.restartUpgradeSingleTitle": "アップグレードを再開", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 485ca11b4fbfc..06fe50fdae469 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -18156,7 +18156,6 @@ "xpack.fleet.upgradeAgents.confirmSingleButtonLabel": "升级代理", "xpack.fleet.upgradeAgents.fatalErrorNotificationTitle": "升级{count, plural, one {代理} other { {count} 个代理} =true {所有选定代理}}时出错", "xpack.fleet.upgradeAgents.noMaintenanceWindowOption": "立即", - "xpack.fleet.upgradeAgents.noVersionsText": "没有任何选定的代理符合升级条件。请选择一个或多个符合条件的代理。", "xpack.fleet.upgradeAgents.restartConfirmMultipleButtonLabel": "重新开始升级{count, plural, one {代理} other { {count} 个代理} =true {所有选定代理}}", "xpack.fleet.upgradeAgents.restartUpgradeMultipleTitle": "在{count, plural, one {代理} other {{count} 个代理} =true {所有代理}}中的 {updating} 个的更新陷入停滞时重新开始升级", "xpack.fleet.upgradeAgents.restartUpgradeSingleTitle": "重新开始升级", From f46fdfc3ce9a3dd6b247c38a04792e59ab17c2a8 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Thu, 4 Jan 2024 13:50:36 +0100 Subject: [PATCH 007/100] [Fleet] Fix form state for input integration (#174248) --- .../services/prepare_input_pkg_policy_dataset.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/prepare_input_pkg_policy_dataset.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/prepare_input_pkg_policy_dataset.ts index 413368772101a..5218583e7212f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/prepare_input_pkg_policy_dataset.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/prepare_input_pkg_policy_dataset.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { cloneDeep } from 'lodash'; + import { DATASET_VAR_NAME } from '../../../../../../../common/constants'; import type { NewPackagePolicy } from '../../../../types'; @@ -14,7 +16,7 @@ export function prepareInputPackagePolicyDataset(newPolicy: NewPackagePolicy): { forceCreateNeeded: boolean; } { let forceCreateNeeded = false; - const { inputs } = newPolicy; + const { inputs } = cloneDeep(newPolicy); if (!inputs || !inputs.length) { return { policy: newPolicy, forceCreateNeeded: false }; From d791a3066e136a03354e4cb82662e254b3c06951 Mon Sep 17 00:00:00 2001 From: Katerina Date: Thu, 4 Jan 2024 15:12:30 +0200 Subject: [PATCH 008/100] [APM] Use ad hoc data view (#173699) ## Summary closes https://github.com/elastic/kibana/issues/172567 Replace and use ad-hoc data views instead of static ones. 1. Metrics dashboard 2. Discover link 3. Mobile geo map Metrics tab https://github.com/elastic/kibana/assets/3369346/ca40c0d7-498c-44a7-80f1-8c225218a7f6 Discover link https://github.com/elastic/kibana/assets/3369346/376d8f2f-6e6a-482b-a829-9963b7b6eeaf ## Note it is worth mentioning that when the links open in a new tab discover app uses the static data view. https://github.com/elastic/kibana/assets/3369346/68984ebc-41ef-4db6-b554-e87b73d201e6 --- .../apm_rule_unified_search_bar.tsx | 4 +- .../context_popover/field_stats_popover.tsx | 4 +- .../app/diagnostics/apm_documents_tab.tsx | 52 +++++------ .../public/components/app/metrics/index.tsx | 6 +- .../app/metrics/static_dashboard/helper.ts | 87 +++++++++++++------ .../app/metrics/static_dashboard/index.tsx | 26 +++--- .../service_overview/geo_map/embedded_map.tsx | 15 ++-- .../mobile/service_overview/geo_map/index.tsx | 4 + .../app/mobile/service_overview/index.tsx | 3 + .../app/service_dashboards/index.tsx | 4 +- .../trace_explorer/trace_search_box/index.tsx | 4 +- .../components/shared/kuery_bar/index.tsx | 4 +- .../links/discover_links/discover_link.tsx | 12 +-- .../discover_links.integration.test.tsx | 29 ++++++- .../shared/search_bar/search_bar.test.tsx | 4 +- .../transaction_action_menu.test.tsx.snap | 4 +- .../transaction_action_menu/sections.ts | 6 +- .../transaction_action_menu.test.tsx | 72 +++++++++++---- .../transaction_action_menu.tsx | 6 +- .../shared/unified_search_bar/index.tsx | 4 +- .../unified_search_bar.test.tsx | 4 +- ...ata_view.ts => use_adhoc_apm_data_view.ts} | 5 +- .../apm/public/hooks/use_data_view_id.tsx | 29 ------- 23 files changed, 229 insertions(+), 159 deletions(-) rename x-pack/plugins/apm/public/hooks/{use_apm_data_view.ts => use_adhoc_apm_data_view.ts} (94%) delete mode 100644 x-pack/plugins/apm/public/hooks/use_data_view_id.tsx diff --git a/x-pack/plugins/apm/public/components/alerting/ui_components/apm_rule_unified_search_bar.tsx b/x-pack/plugins/apm/public/components/alerting/ui_components/apm_rule_unified_search_bar.tsx index 549f394070ce5..fb877ff0ad57a 100644 --- a/x-pack/plugins/apm/public/components/alerting/ui_components/apm_rule_unified_search_bar.tsx +++ b/x-pack/plugins/apm/public/components/alerting/ui_components/apm_rule_unified_search_bar.tsx @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { Query } from '@kbn/es-query'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { ApmPluginStartDeps } from '../../../plugin'; -import { useApmDataView } from '../../../hooks/use_apm_data_view'; +import { useAdHocApmDataView } from '../../../hooks/use_adhoc_apm_data_view'; import { TransactionDurationRuleParams } from '../rule_types/transaction_duration_rule_type'; import { ErrorRateRuleParams } from '../rule_types/transaction_error_rate_rule_type'; import { ErrorCountRuleParams } from '../rule_types/error_count_rule_type'; @@ -36,7 +36,7 @@ export function ApmRuleUnifiedSearchBar({ }, } = services; - const { dataView } = useApmDataView(); + const { dataView } = useAdHocApmDataView(); const searchbarPlaceholder = 'Search for APM data… (e.g. service.name: service-1)'; diff --git a/x-pack/plugins/apm/public/components/app/correlations/context_popover/field_stats_popover.tsx b/x-pack/plugins/apm/public/components/app/correlations/context_popover/field_stats_popover.tsx index b870f1f6ff8dd..8b50a6e9e1ff5 100644 --- a/x-pack/plugins/apm/public/components/app/correlations/context_popover/field_stats_popover.tsx +++ b/x-pack/plugins/apm/public/components/app/correlations/context_popover/field_stats_popover.tsx @@ -44,7 +44,7 @@ import { useApmParams } from '../../../../hooks/use_apm_params'; import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; import { useFetchParams } from '../use_fetch_params'; import type { ApmPluginStartDeps } from '../../../../plugin'; -import { useApmDataView } from '../../../../hooks/use_apm_data_view'; +import { useAdHocApmDataView } from '../../../../hooks/use_adhoc_apm_data_view'; import { useTheme } from '../../../../hooks/use_theme'; import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher'; @@ -214,7 +214,7 @@ export function FieldStatsPopover({ data, core: { uiSettings }, } = useApmPluginContext(); - const { dataView } = useApmDataView(); + const { dataView } = useAdHocApmDataView(); const { services: { fieldFormats, charts }, } = useKibana(); diff --git a/x-pack/plugins/apm/public/components/app/diagnostics/apm_documents_tab.tsx b/x-pack/plugins/apm/public/components/app/diagnostics/apm_documents_tab.tsx index 03fcd2610f23b..52d237af22b7e 100644 --- a/x-pack/plugins/apm/public/components/app/diagnostics/apm_documents_tab.tsx +++ b/x-pack/plugins/apm/public/components/app/diagnostics/apm_documents_tab.tsx @@ -19,8 +19,8 @@ import { orderBy } from 'lodash'; import React, { useMemo, useState } from 'react'; import { asBigNumber, asInteger } from '../../../../common/utils/formatters'; import type { ApmEvent } from '../../../../server/routes/diagnostics/bundle/get_apm_events'; +import { useAdHocApmDataView } from '../../../hooks/use_adhoc_apm_data_view'; import { useApmParams } from '../../../hooks/use_apm_params'; -import { useDataViewId } from '../../../hooks/use_data_view_id'; import { ApmPluginStartDeps } from '../../../plugin'; import { SearchBar } from '../../shared/search_bar/search_bar'; import { useDiagnosticsContext } from './context/use_diagnostics'; @@ -28,7 +28,7 @@ import { useDiagnosticsContext } from './context/use_diagnostics'; export function DiagnosticsApmDocuments() { const { diagnosticsBundle, isImported } = useDiagnosticsContext(); const { discover } = useKibana().services; - const dataViewId = useDataViewId(); + const { dataView } = useAdHocApmDataView(); const [sortField, setSortField] = useState('name'); const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc'); @@ -94,30 +94,32 @@ export function DiagnosticsApmDocuments() { }, { name: 'Actions', - actions: [ - { - name: 'View', - description: 'View in Discover', - type: 'icon', - icon: 'discoverApp', - onClick: async (item) => { - await discover?.locator?.navigate({ - query: { - language: 'kuery', - query: item.kuery, + actions: dataView + ? [ + { + name: 'View', + description: 'View in Discover', + type: 'icon', + icon: 'discoverApp', + onClick: async (item) => { + await discover?.locator?.navigate({ + query: { + language: 'kuery', + query: item.kuery, + }, + dataViewId: dataView?.id ?? '', + timeRange: + rangeTo && rangeFrom + ? { + to: rangeTo, + from: rangeFrom, + } + : undefined, + }); }, - dataViewId, - timeRange: - rangeTo && rangeFrom - ? { - to: rangeTo, - from: rangeFrom, - } - : undefined, - }); - }, - }, - ], + }, + ] + : [], }, ]; diff --git a/x-pack/plugins/apm/public/components/app/metrics/index.tsx b/x-pack/plugins/apm/public/components/app/metrics/index.tsx index 0c70b6fd48d7f..1f86b5a8ceb63 100644 --- a/x-pack/plugins/apm/public/components/app/metrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/metrics/index.tsx @@ -17,11 +17,12 @@ import { ServiceMetrics } from './service_metrics'; import { JvmMetricsOverview } from './jvm_metrics_overview'; import { JsonMetricsDashboard } from './static_dashboard'; import { hasDashboardFile } from './static_dashboard/helper'; +import { useAdHocApmDataView } from '../../../hooks/use_adhoc_apm_data_view'; export function Metrics() { const { agentName, runtimeName, serverlessType } = useApmServiceContext(); const isAWSLambda = isAWSLambdaAgentName(serverlessType); - + const { dataView } = useAdHocApmDataView(); if (isAWSLambda) { return ; } @@ -32,12 +33,13 @@ export function Metrics() { serverlessType, }); - if (hasStaticDashboard) { + if (hasStaticDashboard && dataView) { return ( ); } diff --git a/x-pack/plugins/apm/public/components/app/metrics/static_dashboard/helper.ts b/x-pack/plugins/apm/public/components/app/metrics/static_dashboard/helper.ts index 780e4387b0e10..44db3443cfaf2 100644 --- a/x-pack/plugins/apm/public/components/app/metrics/static_dashboard/helper.ts +++ b/x-pack/plugins/apm/public/components/app/metrics/static_dashboard/helper.ts @@ -5,60 +5,93 @@ * 2.0. */ +import { DataView } from '@kbn/data-views-plugin/common'; import type { DashboardPanelMap } from '@kbn/dashboard-plugin/common'; import { AGENT_NAME_DASHBOARD_FILE_MAPPING, loadDashboardFile, } from './dashboards/dashboard_catalog'; -export interface MetricsDashboardProps { +interface DashboardFileProps { agentName?: string; runtimeName?: string; serverlessType?: string; } -export function hasDashboardFile(props: MetricsDashboardProps) { - return !!getDashboardFile(props); +export interface MetricsDashboardProps extends DashboardFileProps { + dataView: DataView; } -function getDashboardFile({ agentName }: MetricsDashboardProps) { +export function hasDashboardFile(props: DashboardFileProps) { + return !!getDashboardFileName(props); +} + +function getDashboardFileName({ agentName }: DashboardFileProps) { const dashboardFile = agentName && AGENT_NAME_DASHBOARD_FILE_MAPPING[agentName]; return dashboardFile; } -export async function getDashboardPanelMap( +const getAdhocDataView = (dataView: DataView) => { + return { + [dataView.id!]: { + ...dataView, + }, + }; +}; + +export async function convertSavedDashboardToPanels( props: MetricsDashboardProps, - dataViewId: string + dataView: DataView ): Promise { - const dashboardFile = getDashboardFile(props); - const panelsRawObj = !!dashboardFile - ? await loadDashboardFile(dashboardFile) + const dashboardFilename = getDashboardFileName(props); + const dashboardJSON = !!dashboardFilename + ? await loadDashboardFile(dashboardFilename) : undefined; - if (!dashboardFile || !panelsRawObj) { + if (!dashboardFilename || !dashboardJSON) { return undefined; } - const panelsStr: string = ( - panelsRawObj.attributes.panelsJSON as string - ).replaceAll('APM_STATIC_DATA_VIEW_ID', dataViewId); + const panelsRawObjects = JSON.parse( + dashboardJSON.attributes.panelsJSON + ) as any[]; - const panelsRawObjects = JSON.parse(panelsStr) as any[]; + const panels = panelsRawObjects.reduce((acc, panel) => { + const { gridData, embeddableConfig, panelIndex, title } = panel; + const { attributes } = embeddableConfig; + const { state } = attributes; + const { + datasourceStates: { + formBased: { layers }, + }, + } = state; - return panelsRawObjects.reduce( - (acc, panel) => ({ - ...acc, - [panel.gridData.i]: { - type: panel.type, - gridData: panel.gridData, - explicitInput: { - id: panel.panelIndex, - ...panel.embeddableConfig, - title: panel.title, + acc[gridData.i] = { + type: panel.type, + gridData, + explicitInput: { + id: panelIndex, + ...embeddableConfig, + title, + attributes: { + ...attributes, + references: [], + state: { + ...state, + adHocDataViews: getAdhocDataView(dataView), + internalReferences: Object.keys(layers).map((layerId) => ({ + id: dataView.id, + name: `indexpattern-datasource-layer-${layerId}`, + type: 'index-pattern', + })), + }, }, }, - }), - {} - ) as DashboardPanelMap; + }; + + return acc; + }, {}) as DashboardPanelMap; + + return panels; } diff --git a/x-pack/plugins/apm/public/components/app/metrics/static_dashboard/index.tsx b/x-pack/plugins/apm/public/components/app/metrics/static_dashboard/index.tsx index 1498ad8ac4dc7..ce22b13311496 100644 --- a/x-pack/plugins/apm/public/components/app/metrics/static_dashboard/index.tsx +++ b/x-pack/plugins/apm/public/components/app/metrics/static_dashboard/index.tsx @@ -19,21 +19,18 @@ import { i18n } from '@kbn/i18n'; import { controlGroupInputBuilder } from '@kbn/controls-plugin/public'; import { getDefaultControlGroupInput } from '@kbn/controls-plugin/common'; import { NotificationsStart } from '@kbn/core/public'; -import { useDataViewId } from '../../../../hooks/use_data_view_id'; import { ENVIRONMENT_ALL, ENVIRONMENT_NOT_DEFINED, } from '../../../../../common/environment_filter_values'; import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; -import { useApmDataView } from '../../../../hooks/use_apm_data_view'; import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context'; import { useApmParams } from '../../../../hooks/use_apm_params'; -import { getDashboardPanelMap, MetricsDashboardProps } from './helper'; +import { convertSavedDashboardToPanels, MetricsDashboardProps } from './helper'; export function JsonMetricsDashboard(dashboardProps: MetricsDashboardProps) { const [dashboard, setDashboard] = useState(); - const dataViewId = useDataViewId(); - + const { dataView } = dashboardProps; const { query: { environment, kuery, rangeFrom, rangeTo }, } = useApmParams('/services/{serviceName}/metrics'); @@ -42,8 +39,6 @@ export function JsonMetricsDashboard(dashboardProps: MetricsDashboardProps) { core: { notifications }, } = useApmPluginContext(); - const { dataView } = useApmDataView(); - const { serviceName } = useApmServiceContext(); useEffect(() => { @@ -55,21 +50,17 @@ export function JsonMetricsDashboard(dashboardProps: MetricsDashboardProps) { }, [kuery, dashboard, rangeFrom, rangeTo]); useEffect(() => { - if (!dashboard || !dataView) return; + if (!dashboard) return; dashboard.updateInput({ filters: dataView ? getFilters(serviceName, environment, dataView) : [], }); }, [dataView, serviceName, environment, dashboard]); - if (!dataViewId) { - return null; - } - return ( - getCreationOptions(dashboardProps, notifications, dataViewId) + getCreationOptions(dashboardProps, notifications, dataView) } ref={setDashboard} /> @@ -79,20 +70,23 @@ export function JsonMetricsDashboard(dashboardProps: MetricsDashboardProps) { async function getCreationOptions( dashboardProps: MetricsDashboardProps, notifications: NotificationsStart, - dataViewId: string + dataView: DataView ): Promise { try { const builder = controlGroupInputBuilder; const controlGroupInput = getDefaultControlGroupInput(); await builder.addDataControlFromField(controlGroupInput, { - dataViewId, + dataViewId: dataView.id ?? '', title: 'Node name', fieldName: 'service.node.name', width: 'medium', grow: true, }); - const panels = await getDashboardPanelMap(dashboardProps, dataViewId); + const panels = await convertSavedDashboardToPanels( + dashboardProps, + dataView + ); if (!panels) { throw new Error('Failed parsing dashboard panels.'); diff --git a/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/embedded_map.tsx b/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/embedded_map.tsx index ad4f38e7f85f5..80aa35b297bb2 100644 --- a/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/embedded_map.tsx +++ b/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/embedded_map.tsx @@ -6,6 +6,7 @@ */ import React, { useEffect, useState, useRef } from 'react'; +import { DataView } from '@kbn/data-views-plugin/common'; import { v4 as uuidv4 } from 'uuid'; import { MapEmbeddable, @@ -23,7 +24,6 @@ import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import { EuiText } from '@elastic/eui'; import type { Filter } from '@kbn/es-query'; -import { useDataViewId } from '../../../../../hooks/use_data_view_id'; import { ApmPluginStartDeps } from '../../../../../plugin'; import { getLayerList } from './map_layers/get_layer_list'; import { MapTypes } from '../../../../../../common/mobile/constants'; @@ -33,15 +33,16 @@ function EmbeddedMapComponent({ end, kuery = '', filters, + dataView, }: { selectedMap: MapTypes; start: string; end: string; kuery?: string; filters: Filter[]; + dataView?: DataView; }) { const [error, setError] = useState(); - const dataViewId = useDataViewId(); const [embeddable, setEmbeddable] = useState< MapEmbeddable | ErrorEmbeddable | undefined @@ -129,8 +130,12 @@ function EmbeddedMapComponent({ useEffect(() => { const setLayerList = async () => { - if (embeddable && !isErrorEmbeddable(embeddable) && dataViewId) { - const layerList = await getLayerList({ selectedMap, maps, dataViewId }); + if (embeddable && !isErrorEmbeddable(embeddable)) { + const layerList = await getLayerList({ + selectedMap, + maps, + dataViewId: dataView?.id ?? '', + }); await Promise.all([ embeddable.setLayerList(layerList), embeddable.reload(), @@ -139,7 +144,7 @@ function EmbeddedMapComponent({ }; setLayerList(); - }, [embeddable, selectedMap, maps, dataViewId]); + }, [embeddable, selectedMap, maps, dataView]); useEffect(() => { if (embeddable) { diff --git a/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/index.tsx b/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/index.tsx index 750ec795a236c..ed49a521b9d02 100644 --- a/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/index.tsx +++ b/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/index.tsx @@ -6,6 +6,7 @@ */ import React, { useState } from 'react'; +import { DataView } from '@kbn/data-views-plugin/common'; import { EuiSpacer } from '@elastic/eui'; import type { Filter } from '@kbn/es-query'; import { EmbeddedMap } from './embedded_map'; @@ -17,11 +18,13 @@ export function GeoMap({ end, kuery, filters, + dataView, }: { start: string; end: string; kuery?: string; filters: Filter[]; + dataView?: DataView; }) { const [selectedMap, selectMap] = useState(MapTypes.Http); @@ -40,6 +43,7 @@ export function GeoMap({ end={end} kuery={kuery} filters={filters} + dataView={dataView} />
diff --git a/x-pack/plugins/apm/public/components/app/mobile/service_overview/index.tsx b/x-pack/plugins/apm/public/components/app/mobile/service_overview/index.tsx index 28cecf554142a..55104eefaa071 100644 --- a/x-pack/plugins/apm/public/components/app/mobile/service_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/mobile/service_overview/index.tsx @@ -34,6 +34,7 @@ import { useFiltersForEmbeddableCharts } from '../../../../hooks/use_filters_for import { getKueryWithMobileFilters } from '../../../../../common/utils/get_kuery_with_mobile_filters'; import { MobileStats } from './stats/stats'; import { MobileLocationStats } from './stats/location_stats'; +import { useAdHocApmDataView } from '../../../../hooks/use_adhoc_apm_data_view'; /** * The height a chart should be if it's next to a table with 5 rows and a title. * Add the height of the pagination row. @@ -43,6 +44,7 @@ export const chartHeight = 288; export function MobileServiceOverview() { const { serviceName } = useApmServiceContext(); const router = useApmRouter(); + const { dataView } = useAdHocApmDataView(); const { query, @@ -122,6 +124,7 @@ export function MobileServiceOverview() { end={end} kuery={kueryWithMobileFilters} filters={embeddableFilters} + dataView={dataView} /> diff --git a/x-pack/plugins/apm/public/components/app/service_dashboards/index.tsx b/x-pack/plugins/apm/public/components/app/service_dashboards/index.tsx index b4972eafbe3f0..fe44d62c2388d 100644 --- a/x-pack/plugins/apm/public/components/app/service_dashboards/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_dashboards/index.tsx @@ -34,7 +34,7 @@ import { ContextMenu } from './context_menu'; import { UnlinkDashboard } from './actions/unlink_dashboard'; import { EditDashboard } from './actions/edit_dashboard'; import { DashboardSelector } from './dashboard_selector'; -import { useApmDataView } from '../../../hooks/use_apm_data_view'; +import { useAdHocApmDataView } from '../../../hooks/use_adhoc_apm_data_view'; import { getFilters } from '../metrics/static_dashboard'; import { useDashboardFetcher } from '../../../hooks/use_dashboards_fetcher'; import { useTimeRange } from '../../../hooks/use_time_range'; @@ -58,7 +58,7 @@ export function ServiceDashboards() { useState(); const { data: allAvailableDashboards } = useDashboardFetcher(); const { start, end } = useTimeRange({ rangeFrom, rangeTo }); - const { dataView } = useApmDataView(); + const { dataView } = useAdHocApmDataView(); const { share } = useApmPluginContext(); const { data, status, refetch } = useFetcher( diff --git a/x-pack/plugins/apm/public/components/app/trace_explorer/trace_search_box/index.tsx b/x-pack/plugins/apm/public/components/app/trace_explorer/trace_search_box/index.tsx index 0995f8555ae29..9f26d27e316c8 100644 --- a/x-pack/plugins/apm/public/components/app/trace_explorer/trace_search_box/index.tsx +++ b/x-pack/plugins/apm/public/components/app/trace_explorer/trace_search_box/index.tsx @@ -17,7 +17,7 @@ import { TraceSearchQuery, TraceSearchType, } from '../../../../../common/trace_explorer'; -import { useApmDataView } from '../../../../hooks/use_apm_data_view'; +import { useAdHocApmDataView } from '../../../../hooks/use_adhoc_apm_data_view'; import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; import { EQLCodeEditor } from '../../../shared/monaco_code_editor'; @@ -57,7 +57,7 @@ export function TraceSearchBox({ }, } = useApmPluginContext(); - const { dataView } = useApmDataView(); + const { dataView } = useAdHocApmDataView(); return ( diff --git a/x-pack/plugins/apm/public/components/shared/kuery_bar/index.tsx b/x-pack/plugins/apm/public/components/shared/kuery_bar/index.tsx index 5c5c59f85a0aa..c1f37525ebea6 100644 --- a/x-pack/plugins/apm/public/components/shared/kuery_bar/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/kuery_bar/index.tsx @@ -16,7 +16,7 @@ import type { DataView } from '@kbn/data-views-plugin/public'; import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; import { useLegacyUrlParams } from '../../../context/url_params_context/use_url_params'; import { useApmParams } from '../../../hooks/use_apm_params'; -import { useApmDataView } from '../../../hooks/use_apm_data_view'; +import { useAdHocApmDataView } from '../../../hooks/use_adhoc_apm_data_view'; import { fromQuery, toQuery } from '../links/url_helpers'; import { getBoolFilter } from '../get_bool_filter'; import { Typeahead } from './typeahead'; @@ -71,7 +71,7 @@ export function KueryBar(props: { }; const example = examples[processorEvent || 'defaults']; - const { dataView } = useApmDataView(); + const { dataView } = useAdHocApmDataView(); const placeholder = props.placeholder ?? diff --git a/x-pack/plugins/apm/public/components/shared/links/discover_links/discover_link.tsx b/x-pack/plugins/apm/public/components/shared/links/discover_links/discover_link.tsx index 987fe5b23de52..4ae212c44ee13 100644 --- a/x-pack/plugins/apm/public/components/shared/links/discover_links/discover_link.tsx +++ b/x-pack/plugins/apm/public/components/shared/links/discover_links/discover_link.tsx @@ -5,16 +5,16 @@ * 2.0. */ -import { EuiLink } from '@elastic/eui'; +import { EuiLink, EuiLoadingSpinner } from '@elastic/eui'; import { Location } from 'history'; import { IBasePath } from '@kbn/core/public'; import React from 'react'; import { useLocation } from 'react-router-dom'; import rison from '@kbn/rison'; import url from 'url'; -import { useDataViewId } from '../../../../hooks/use_data_view_id'; import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; import { getTimepickerRisonData } from '../rison_helpers'; +import { useAdHocApmDataView } from '../../../../hooks/use_adhoc_apm_data_view'; interface Props { query: { @@ -64,17 +64,17 @@ export const getDiscoverHref = ({ export function DiscoverLink({ query = {}, ...rest }: Props) { const { core } = useApmPluginContext(); const location = useLocation(); - const dataViewId = useDataViewId(); + const { dataView } = useAdHocApmDataView(); - if (!dataViewId) { - return null; + if (!dataView) { + return ; } const href = getDiscoverHref({ basePath: core.http.basePath, query, location, - dataViewId, + dataViewId: dataView?.id ?? '', }); return ; diff --git a/x-pack/plugins/apm/public/components/shared/links/discover_links/discover_links.integration.test.tsx b/x-pack/plugins/apm/public/components/shared/links/discover_links/discover_links.integration.test.tsx index 4d79e5e8f2796..092278fdd9cbc 100644 --- a/x-pack/plugins/apm/public/components/shared/links/discover_links/discover_links.integration.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/links/discover_links/discover_links.integration.test.tsx @@ -10,12 +10,33 @@ import React from 'react'; import { APMError } from '../../../../../typings/es_schemas/ui/apm_error'; import { Span } from '../../../../../typings/es_schemas/ui/span'; import { Transaction } from '../../../../../typings/es_schemas/ui/transaction'; +import * as useAdHocApmDataView from '../../../../hooks/use_adhoc_apm_data_view'; import { getRenderedHref } from '../../../../utils/test_helpers'; import { DiscoverErrorLink } from './discover_error_link'; import { DiscoverSpanLink } from './discover_span_link'; import { DiscoverTransactionLink } from './discover_transaction_link'; describe('DiscoverLinks', () => { + let useAdHocApmDataViewSpy: jest.SpyInstance; + + beforeAll(() => { + useAdHocApmDataViewSpy = jest.spyOn( + useAdHocApmDataView, + 'useAdHocApmDataView' + ); + + useAdHocApmDataViewSpy.mockImplementation(() => { + return { + dataView: { + id: 'foo-1', + }, + }; + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); it('produces the correct URL for a transaction', async () => { const transaction = { transaction: { @@ -35,7 +56,7 @@ describe('DiscoverLinks', () => { ); expect(href).toMatchInlineSnapshot( - `"/basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now))&_a=(index:apm_static_data_view_id_mockSpaceId,interval:auto,query:(language:kuery,query:'processor.event:\\"transaction\\" AND transaction.id:\\"8b60bd32ecc6e150\\" AND trace.id:\\"8b60bd32ecc6e1506735a8b6cfcf175c\\"'))"` + `"/basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now))&_a=(index:foo-1,interval:auto,query:(language:kuery,query:'processor.event:\\"transaction\\" AND transaction.id:\\"8b60bd32ecc6e150\\" AND trace.id:\\"8b60bd32ecc6e1506735a8b6cfcf175c\\"'))"` ); }); @@ -55,7 +76,7 @@ describe('DiscoverLinks', () => { ); expect(href).toMatchInlineSnapshot( - `"/basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now))&_a=(index:apm_static_data_view_id_mockSpaceId,interval:auto,query:(language:kuery,query:'span.id:\\"test-span-id\\"'))"` + `"/basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now))&_a=(index:foo-1,interval:auto,query:(language:kuery,query:'span.id:\\"test-span-id\\"'))"` ); }); @@ -77,7 +98,7 @@ describe('DiscoverLinks', () => { ); expect(href).toMatchInlineSnapshot( - `"/basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now))&_a=(index:apm_static_data_view_id_mockSpaceId,interval:auto,query:(language:kuery,query:'service.name:\\"service-name\\" AND error.grouping_key:\\"grouping-key\\"'),sort:('@timestamp':desc))"` + `"/basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now))&_a=(index:foo-1,interval:auto,query:(language:kuery,query:'service.name:\\"service-name\\" AND error.grouping_key:\\"grouping-key\\"'),sort:('@timestamp':desc))"` ); }); @@ -100,7 +121,7 @@ describe('DiscoverLinks', () => { ); expect(href).toMatchInlineSnapshot( - `"/basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now))&_a=(index:apm_static_data_view_id_mockSpaceId,interval:auto,query:(language:kuery,query:'service.name:\\"service-name\\" AND error.grouping_key:\\"grouping-key\\" AND some:kuery-string'),sort:('@timestamp':desc))"` + `"/basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now))&_a=(index:foo-1,interval:auto,query:(language:kuery,query:'service.name:\\"service-name\\" AND error.grouping_key:\\"grouping-key\\" AND some:kuery-string'),sort:('@timestamp':desc))"` ); }); }); diff --git a/x-pack/plugins/apm/public/components/shared/search_bar/search_bar.test.tsx b/x-pack/plugins/apm/public/components/shared/search_bar/search_bar.test.tsx index 5713390de48f7..c3ed213e8ebab 100644 --- a/x-pack/plugins/apm/public/components/shared/search_bar/search_bar.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/search_bar/search_bar.test.tsx @@ -14,7 +14,7 @@ import { ApmServiceContextProvider } from '../../../context/apm_service/apm_serv import { UrlParamsProvider } from '../../../context/url_params_context/url_params_context'; import type { ApmUrlParams } from '../../../context/url_params_context/types'; import * as useFetcherHook from '../../../hooks/use_fetcher'; -import * as useApmDataViewHook from '../../../hooks/use_apm_data_view'; +import * as useApmDataViewHook from '../../../hooks/use_adhoc_apm_data_view'; import * as useServiceTransactionTypesHook from '../../../context/apm_service/use_service_transaction_types_fetcher'; import { renderWithTheme } from '../../../utils/test_helpers'; import { fromQuery } from '../links/url_helpers'; @@ -71,7 +71,7 @@ function setup({ // mock transaction types jest - .spyOn(useApmDataViewHook, 'useApmDataView') + .spyOn(useApmDataViewHook, 'useAdHocApmDataView') .mockReturnValue({ dataView: undefined }); jest.spyOn(useFetcherHook, 'useFetcher').mockReturnValue({} as any); diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/__snapshots__/transaction_action_menu.test.tsx.snap b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/__snapshots__/transaction_action_menu.test.tsx.snap index 02ed85e387ecb..023caad499485 100644 --- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/__snapshots__/transaction_action_menu.test.tsx.snap +++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/__snapshots__/transaction_action_menu.test.tsx.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`TransactionActionMenu component matches the snapshot 1`] = ` +exports[`TransactionActionMenu matches the snapshot 1`] = `
+ + + + + + + ); +}; + +export const RiskSummary = React.memo(RiskSummaryComponent); RiskSummary.displayName = 'RiskSummary'; diff --git a/x-pack/plugins/security_solution/public/explore/hosts/containers/hosts/details/index.tsx b/x-pack/plugins/security_solution/public/explore/hosts/containers/hosts/details/index.tsx index f6ea1ff14a264..490891732abd4 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/containers/hosts/details/index.tsx +++ b/x-pack/plugins/security_solution/public/explore/hosts/containers/hosts/details/index.tsx @@ -42,7 +42,7 @@ export const useHostDetails = ({ id = ID, skip = false, startDate, -}: UseHostDetails): [boolean, HostDetailsArgs] => { +}: UseHostDetails): [boolean, HostDetailsArgs, inputsModel.Refetch] => { const { loading, result: response, @@ -91,5 +91,5 @@ export const useHostDetails = ({ } }, [hostDetailsRequest, search, skip]); - return [loading, hostDetailsResponse]; + return [loading, hostDetailsResponse, refetch]; }; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_details_left/index.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_details_left/index.test.tsx new file mode 100644 index 0000000000000..82cf0f8ff9f56 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_details_left/index.test.tsx @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { RISK_INPUTS_TAB_TEST_ID } from '../../../entity_analytics/components/entity_details_flyout'; +import { render } from '@testing-library/react'; +import React from 'react'; +import { HostDetailsPanel } from '.'; +import { TestProviders } from '../../../common/mock'; + +describe('HostDetailsPanel', () => { + it('render risk inputs panel', () => { + const { getByTestId } = render( + , + { wrapper: TestProviders } + ); + expect(getByTestId(RISK_INPUTS_TAB_TEST_ID)).toBeInTheDocument(); + }); + + it("doesn't render risk inputs panel when no alerts ids are provided", () => { + const { queryByTestId } = render( + , + { wrapper: TestProviders } + ); + expect(queryByTestId(RISK_INPUTS_TAB_TEST_ID)).not.toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_details_left/index.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_details_left/index.tsx new file mode 100644 index 0000000000000..3214dec23bdd6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_details_left/index.tsx @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import type { FlyoutPanelProps } from '@kbn/expandable-flyout'; +import { getRiskInputTab } from '../../../entity_analytics/components/entity_details_flyout'; +import { LeftPanelContent } from '../shared/components/left_panel/left_panel_content'; +import { + EntityDetailsLeftPanelTab, + LeftPanelHeader, +} from '../shared/components/left_panel/left_panel_header'; + +interface RiskInputsParam { + alertIds: string[]; +} + +export interface HostDetailsPanelProps extends Record { + riskInputs: RiskInputsParam; +} +export interface HostDetailsExpandableFlyoutProps extends FlyoutPanelProps { + key: 'host_details'; + params: HostDetailsPanelProps; +} +export const HostDetailsPanelKey: HostDetailsExpandableFlyoutProps['key'] = 'host_details'; + +export const HostDetailsPanel = ({ riskInputs }: HostDetailsPanelProps) => { + // Temporary implementation while Host details left panel don't have Asset tabs + const [tabs, selectedTabId, setSelectedTabId] = useMemo(() => { + return [ + riskInputs.alertIds.length > 0 ? [getRiskInputTab(riskInputs.alertIds)] : [], + EntityDetailsLeftPanelTab.RISK_INPUTS, + () => {}, + ]; + }, [riskInputs.alertIds]); + + return ( + <> + + + + ); +}; + +HostDetailsPanel.displayName = 'HostDetailsPanel'; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/content.stories.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/content.stories.tsx new file mode 100644 index 0000000000000..9bea5cb2a4ac2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/content.stories.tsx @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { storiesOf } from '@storybook/react'; +import { EuiFlyout } from '@elastic/eui'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/context'; +import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; +import { StorybookProviders } from '../../../common/mock/storybook_providers'; +import { mockRiskScoreState } from '../../../timelines/components/side_panel/new_user_detail/__mocks__'; +import { HostPanelContent } from './content'; +import { mockObservedHostData } from '../mocks'; + +const flyoutContextValue = { + openLeftPanel: () => window.alert('openLeftPanel called'), + panels: {}, +} as unknown as ExpandableFlyoutContextValue; + +const riskScoreData = { ...mockRiskScoreState, data: [] }; + +storiesOf('Components/HostPanelContent', module) + .addDecorator((storyFn) => ( + + + {}}> + {storyFn()} + + + + )) + .add('default', () => ( + {}} + /> + )) + .add('no observed data', () => ( + {}} + /> + )) + .add('loading', () => ( + {}} + /> + )); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/content.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/content.tsx new file mode 100644 index 0000000000000..eb7d5f3fda26d --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/content.tsx @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiHorizontalRule } from '@elastic/eui'; + +import React from 'react'; +import { RiskSummary } from '../../../entity_analytics/components/risk_summary_flyout/risk_summary'; +import type { RiskScoreState } from '../../../entity_analytics/api/hooks/use_risk_score'; +import type { RiskScoreEntity, HostItem } from '../../../../common/search_strategy'; +import { FlyoutBody } from '../../shared/components/flyout_body'; +import { ObservedEntity } from '../shared/components/observed_entity'; +import { HOST_PANEL_OBSERVED_HOST_QUERY_ID, HOST_PANEL_RISK_SCORE_QUERY_ID } from '.'; +import type { ObservedEntityData } from '../shared/components/observed_entity/types'; +import { useObservedHostFields } from './hooks/use_observed_host_fields'; +import type { EntityDetailsLeftPanelTab } from '../shared/components/left_panel/left_panel_header'; + +interface HostPanelContentProps { + observedHost: ObservedEntityData; + riskScoreState: RiskScoreState; + contextID: string; + scopeId: string; + isDraggable: boolean; + openDetailsPanel: (tab: EntityDetailsLeftPanelTab) => void; +} + +export const HostPanelContent = ({ + observedHost, + riskScoreState, + contextID, + scopeId, + isDraggable, + openDetailsPanel, +}: HostPanelContentProps) => { + const observedFields = useObservedHostFields(observedHost); + + return ( + + {riskScoreState.isModuleEnabled && riskScoreState.data?.length !== 0 && ( + <> + { + + } + + + )} + + + ); +}; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/basic_host_fields.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/basic_host_fields.tsx new file mode 100644 index 0000000000000..1229a08e7c956 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/basic_host_fields.tsx @@ -0,0 +1,80 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { getEmptyTagValue } from '../../../../common/components/empty_value'; +import type { HostItem } from '../../../../../common/search_strategy'; +import { FormattedRelativePreferenceDate } from '../../../../common/components/formatted_date'; +import { NetworkDetailsLink } from '../../../../common/components/links'; +import * as i18n from './translations'; +import type { ObservedEntityData } from '../../shared/components/observed_entity/types'; +import type { EntityTableRows } from '../../shared/components/entity_table/types'; + +export const basicHostFields: EntityTableRows> = [ + { + label: i18n.HOST_ID, + getValues: (hostData: ObservedEntityData) => hostData.details.host?.id, + field: 'host.id', + }, + { + label: i18n.FIRST_SEEN, + render: (hostData: ObservedEntityData) => + hostData.firstSeen.date ? ( + + ) : ( + getEmptyTagValue() + ), + }, + { + label: i18n.LAST_SEEN, + render: (hostData: ObservedEntityData) => + hostData.lastSeen.date ? ( + + ) : ( + getEmptyTagValue() + ), + }, + { + label: i18n.IP_ADDRESSES, + field: 'host.ip', + getValues: (hostData: ObservedEntityData) => hostData.details.host?.ip, + renderField: (ip: string) => { + return ; + }, + }, + { + label: i18n.MAC_ADDRESSES, + getValues: (hostData: ObservedEntityData) => hostData.details.host?.mac, + field: 'host.mac', + }, + { + label: i18n.PLATFORM, + getValues: (hostData: ObservedEntityData) => hostData.details.host?.os?.platform, + field: 'host.os.platform', + }, + { + label: i18n.OS, + getValues: (hostData: ObservedEntityData) => hostData.details.host?.os?.name, + field: 'host.os.name', + }, + { + label: i18n.FAMILY, + getValues: (hostData: ObservedEntityData) => hostData.details.host?.os?.family, + field: 'host.os.family', + }, + { + label: i18n.VERSION, + getValues: (hostData: ObservedEntityData) => hostData.details.host?.os?.version, + field: 'host.os.version', + }, + { + label: i18n.ARCHITECTURE, + getValues: (hostData: ObservedEntityData) => hostData.details.host?.architecture, + field: 'host.architecture', + }, +]; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/cloud_fields.ts b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/cloud_fields.ts new file mode 100644 index 0000000000000..c4ea144a7db06 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/cloud_fields.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { HostItem } from '../../../../../common/search_strategy'; +import type { EntityTableRows } from '../../shared/components/entity_table/types'; +import type { ObservedEntityData } from '../../shared/components/observed_entity/types'; +import * as i18n from './translations'; + +export const cloudFields: EntityTableRows> = [ + { + label: i18n.CLOUD_PROVIDER, + getValues: (hostData: ObservedEntityData) => hostData.details.cloud?.provider, + field: 'cloud.provider', + }, + { + label: i18n.REGION, + getValues: (hostData: ObservedEntityData) => hostData.details.cloud?.region, + field: 'cloud.region', + }, + { + label: i18n.INSTANCE_ID, + getValues: (hostData: ObservedEntityData) => hostData.details.cloud?.instance?.id, + field: 'cloud.instance.id', + }, + { + label: i18n.MACHINE_TYPE, + getValues: (hostData: ObservedEntityData) => hostData.details.cloud?.machine?.type, + field: 'cloud.machine.type', + }, +]; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/endpoint_policy_fields.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/endpoint_policy_fields.test.tsx new file mode 100644 index 0000000000000..a8ba12de451e3 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/endpoint_policy_fields.test.tsx @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { TestProviders } from '../../../../common/mock'; +import { render } from '@testing-library/react'; +import React from 'react'; +import { mockObservedHostData } from '../../mocks'; +import { policyFields } from './endpoint_policy_fields'; + +const TestWrapper = ({ el }: { el: JSX.Element | undefined }) => <>{el}; + +jest.mock( + '../../../../management/hooks/response_actions/use_get_endpoint_pending_actions_summary', + () => { + const original = jest.requireActual( + '../../../../management/hooks/response_actions/use_get_endpoint_pending_actions_summary' + ); + return { + ...original, + useGetEndpointPendingActionsSummary: () => ({ + pendingActions: [], + isLoading: false, + isError: false, + isTimeout: false, + fetch: jest.fn(), + }), + }; + } +); + +describe('Endpoint Policy Fields', () => { + it('renders policy name', () => { + const policyName = policyFields[0]; + + const { container } = render(); + + expect(container).toHaveTextContent('policy-name'); + }); + + it('renders policy status', () => { + const policyStatus = policyFields[1]; + + const { container } = render(); + + expect(container).toHaveTextContent('failure'); + }); + + it('renders agent status', () => { + const agentStatus = policyFields[3]; + + const { container } = render(, { + wrapper: TestProviders, + }); + + expect(container).toHaveTextContent('Healthy'); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/endpoint_policy_fields.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/endpoint_policy_fields.tsx new file mode 100644 index 0000000000000..fd9b8c744a7b2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/endpoint_policy_fields.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 React from 'react'; +import { EuiHealth } from '@elastic/eui'; + +import type { EntityTableRows } from '../../shared/components/entity_table/types'; +import type { ObservedEntityData } from '../../shared/components/observed_entity/types'; +import { EndpointAgentStatus } from '../../../../common/components/endpoint/endpoint_agent_status'; +import { getEmptyTagValue } from '../../../../common/components/empty_value'; +import type { HostItem } from '../../../../../common/search_strategy'; +import { HostPolicyResponseActionStatus } from '../../../../../common/search_strategy'; +import * as i18n from './translations'; + +export const policyFields: EntityTableRows> = [ + { + label: i18n.ENDPOINT_POLICY, + render: (hostData: ObservedEntityData) => { + const appliedPolicy = hostData.details.endpoint?.hostInfo?.metadata.Endpoint.policy.applied; + return appliedPolicy?.name ? <>{appliedPolicy.name} : getEmptyTagValue(); + }, + isVisible: (hostData: ObservedEntityData) => hostData.details.endpoint != null, + }, + { + label: i18n.POLICY_STATUS, + render: (hostData: ObservedEntityData) => { + const appliedPolicy = hostData.details.endpoint?.hostInfo?.metadata.Endpoint.policy.applied; + const policyColor = + appliedPolicy?.status === HostPolicyResponseActionStatus.failure + ? 'danger' + : appliedPolicy?.status; + + return appliedPolicy?.status ? ( + + {appliedPolicy?.status} + + ) : ( + getEmptyTagValue() + ); + }, + isVisible: (hostData: ObservedEntityData) => hostData.details.endpoint != null, + }, + { + label: i18n.SENSORVERSION, + getValues: (hostData: ObservedEntityData) => + hostData.details.endpoint?.hostInfo?.metadata.agent.version + ? [hostData.details.endpoint?.hostInfo?.metadata.agent.version] + : undefined, + field: 'agent.version', + isVisible: (hostData: ObservedEntityData) => hostData.details.endpoint != null, + }, + { + label: i18n.FLEET_AGENT_STATUS, + render: (hostData: ObservedEntityData) => + hostData.details.endpoint?.hostInfo ? ( + + ) : ( + getEmptyTagValue() + ), + isVisible: (hostData: ObservedEntityData) => hostData.details.endpoint != null, + }, +]; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/translations.ts b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/translations.ts new file mode 100644 index 0000000000000..dac45a3a6202c --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/translations.ts @@ -0,0 +1,131 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 HOST_ID = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.host.hostIdTitle', + { + defaultMessage: 'Host ID', + } +); + +export const FIRST_SEEN = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.host.firstSeenTitle', + { + defaultMessage: 'First seen', + } +); + +export const LAST_SEEN = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.host.lastSeenTitle', + { + defaultMessage: 'Last seen', + } +); + +export const IP_ADDRESSES = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.host.ipAddressesTitle', + { + defaultMessage: 'IP addresses', + } +); + +export const MAC_ADDRESSES = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.host.macAddressesTitle', + { + defaultMessage: 'MAC addresses', + } +); + +export const PLATFORM = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.host.platformTitle', + { + defaultMessage: 'Platform', + } +); + +export const OS = i18n.translate('xpack.securitySolution.flyout.entityDetails.host.osTitle', { + defaultMessage: 'Operating system', +}); + +export const FAMILY = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.host.familyTitle', + { + defaultMessage: 'Family', + } +); + +export const VERSION = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.host.versionLabel', + { + defaultMessage: 'Version', + } +); + +export const ARCHITECTURE = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.host.architectureLabel', + { + defaultMessage: 'Architecture', + } +); + +export const CLOUD_PROVIDER = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.host.cloudProviderTitle', + { + defaultMessage: 'Cloud provider', + } +); + +export const REGION = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.host.regionTitle', + { + defaultMessage: 'Region', + } +); + +export const INSTANCE_ID = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.host.instanceIdTitle', + { + defaultMessage: 'Instance ID', + } +); + +export const MACHINE_TYPE = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.host.machineTypeTitle', + { + defaultMessage: 'Machine type', + } +); + +export const ENDPOINT_POLICY = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.host.endpoint.endpointPolicy', + { + defaultMessage: 'Endpoint integration policy', + } +); + +export const POLICY_STATUS = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.host.endpoint.policyStatus', + { + defaultMessage: 'Policy Status', + } +); + +export const SENSORVERSION = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.host.endpoint.sensorversion', + { + defaultMessage: 'Endpoint version', + } +); + +export const FLEET_AGENT_STATUS = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.host.endpoint.fleetAgentStatus', + { + defaultMessage: 'Agent status', + } +); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/header.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/header.test.tsx new file mode 100644 index 0000000000000..418ec64cb6709 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/header.test.tsx @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 '../../../common/mock'; +import { HostPanelHeader } from './header'; +import { mockObservedHostData } from '../mocks'; + +const mockProps = { + hostName: 'test', + observedHost: mockObservedHostData, +}; + +jest.mock('../../../common/components/visualization_actions/visualization_embeddable'); + +describe('HostPanelHeader', () => { + it('renders', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('host-panel-header')).toBeInTheDocument(); + }); + + it('renders observed date', () => { + const futureDay = '2989-03-07T20:00:00.000Z'; + const { getByTestId } = render( + + + + ); + + expect(getByTestId('host-panel-header-lastSeen').textContent).toContain('Mar 7, 2989'); + }); + + it('renders observed badge when lastSeen is defined', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('host-panel-header-observed-badge')).toBeInTheDocument(); + }); + + it('does not render observed badge when lastSeen date is undefined', () => { + const { queryByTestId } = render( + + + + ); + + expect(queryByTestId('host-panel-header-observed-badge')).not.toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/header.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/header.tsx new file mode 100644 index 0000000000000..e8785a92acb6d --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/header.tsx @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiSpacer, EuiBadge, EuiText, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import React, { useMemo } from 'react'; +import { SecurityPageName } from '@kbn/security-solution-navigation'; +import type { HostItem } from '../../../../common/search_strategy'; +import { getHostDetailsUrl } from '../../../common/components/link_to'; +import { SecuritySolutionLinkAnchor } from '../../../common/components/links'; +import { PreferenceFormattedDate } from '../../../common/components/formatted_date'; +import { FlyoutHeader } from '../../shared/components/flyout_header'; +import { FlyoutTitle } from '../../shared/components/flyout_title'; +import type { ObservedEntityData } from '../shared/components/observed_entity/types'; + +interface HostPanelHeaderProps { + hostName: string; + observedHost: ObservedEntityData; +} + +export const HostPanelHeader = ({ hostName, observedHost }: HostPanelHeaderProps) => { + const lastSeenDate = useMemo( + () => observedHost.lastSeen.date && new Date(observedHost.lastSeen.date), + [observedHost.lastSeen.date] + ); + + return ( + + + + + {lastSeenDate && } + + + + + + + + + + + + {observedHost.lastSeen.date && ( + + + + )} + + + + + + ); +}; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/hooks/use_observed_host.ts b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/hooks/use_observed_host.ts new file mode 100644 index 0000000000000..980407b034649 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/hooks/use_observed_host.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useMemo } from 'react'; +import { useHostDetails } from '../../../../explore/hosts/containers/hosts/details'; +import { useFirstLastSeen } from '../../../../common/containers/use_first_last_seen'; +import { useGlobalTime } from '../../../../common/containers/use_global_time'; +import { useSourcererDataView } from '../../../../common/containers/sourcerer'; +import type { HostItem } from '../../../../../common/search_strategy'; +import { Direction, NOT_EVENT_KIND_ASSET_FILTER } from '../../../../../common/search_strategy'; +import { HOST_PANEL_OBSERVED_HOST_QUERY_ID, HOST_PANEL_RISK_SCORE_QUERY_ID } from '..'; +import { useQueryInspector } from '../../../../common/components/page/manage_query'; +import type { ObservedEntityData } from '../../shared/components/observed_entity/types'; + +export const useObservedHost = ( + hostName: string +): Omit, 'anomalies'> => { + const { to, from, isInitializing, setQuery, deleteQuery } = useGlobalTime(); + const { selectedPatterns } = useSourcererDataView(); + + const [isLoading, { hostDetails, inspect: inspectObservedHost }, refetch] = useHostDetails({ + endDate: to, + hostName, + indexNames: selectedPatterns, + id: HOST_PANEL_RISK_SCORE_QUERY_ID, + skip: isInitializing, + startDate: from, + }); + + useQueryInspector({ + deleteQuery, + inspect: inspectObservedHost, + loading: isLoading, + queryId: HOST_PANEL_OBSERVED_HOST_QUERY_ID, + refetch, + setQuery, + }); + + const [loadingFirstSeen, { firstSeen }] = useFirstLastSeen({ + field: 'host.name', + value: hostName, + defaultIndex: selectedPatterns, + order: Direction.asc, + filterQuery: NOT_EVENT_KIND_ASSET_FILTER, + }); + + const [loadingLastSeen, { lastSeen }] = useFirstLastSeen({ + field: 'host.name', + value: hostName, + defaultIndex: selectedPatterns, + order: Direction.desc, + filterQuery: NOT_EVENT_KIND_ASSET_FILTER, + }); + + return useMemo( + () => ({ + details: hostDetails, + isLoading: isLoading || loadingLastSeen || loadingFirstSeen, + firstSeen: { + date: firstSeen, + isLoading: loadingFirstSeen, + }, + lastSeen: { date: lastSeen, isLoading: loadingLastSeen }, + }), + [firstSeen, hostDetails, isLoading, lastSeen, loadingFirstSeen, loadingLastSeen] + ); +}; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/hooks/use_observed_host_fields.test.ts b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/hooks/use_observed_host_fields.test.ts new file mode 100644 index 0000000000000..ea37bf40bfeef --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/hooks/use_observed_host_fields.test.ts @@ -0,0 +1,143 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { useObservedHostFields } from './use_observed_host_fields'; +import { TestProviders } from '@kbn/timelines-plugin/public/mock'; +import { mockObservedHostData } from '../../mocks'; + +describe('useManagedUserItems', () => { + it('returns managed user items for Entra user', () => { + const { result } = renderHook(() => useObservedHostFields(mockObservedHostData), { + wrapper: TestProviders, + }); + + expect(result.current).toMatchInlineSnapshot(` + Array [ + Object { + "field": "host.id", + "getValues": [Function], + "label": "Host ID", + }, + Object { + "label": "First seen", + "render": [Function], + }, + Object { + "label": "Last seen", + "render": [Function], + }, + Object { + "field": "host.ip", + "getValues": [Function], + "label": "IP addresses", + "renderField": [Function], + }, + Object { + "field": "host.mac", + "getValues": [Function], + "label": "MAC addresses", + }, + Object { + "field": "host.os.platform", + "getValues": [Function], + "label": "Platform", + }, + Object { + "field": "host.os.name", + "getValues": [Function], + "label": "Operating system", + }, + Object { + "field": "host.os.family", + "getValues": [Function], + "label": "Family", + }, + Object { + "field": "host.os.version", + "getValues": [Function], + "label": "Version", + }, + Object { + "field": "host.architecture", + "getValues": [Function], + "label": "Architecture", + }, + Object { + "isVisible": [Function], + "label": "Max anomaly score by job", + "render": [Function], + }, + Object { + "field": "cloud.provider", + "getValues": [Function], + "label": "Cloud provider", + }, + Object { + "field": "cloud.region", + "getValues": [Function], + "label": "Region", + }, + Object { + "field": "cloud.instance.id", + "getValues": [Function], + "label": "Instance ID", + }, + Object { + "field": "cloud.machine.type", + "getValues": [Function], + "label": "Machine type", + }, + Object { + "isVisible": [Function], + "label": "Endpoint integration policy", + "render": [Function], + }, + Object { + "isVisible": [Function], + "label": "Policy Status", + "render": [Function], + }, + Object { + "field": "agent.version", + "getValues": [Function], + "isVisible": [Function], + "label": "Endpoint version", + }, + Object { + "isVisible": [Function], + "label": "Agent status", + "render": [Function], + }, + ] + `); + + expect( + result.current.map(({ getValues }) => getValues && getValues(mockObservedHostData)) + ).toEqual([ + ['host-id'], + undefined, // First seen doesn't implement getValues + undefined, // Last seen doesn't implement getValues + ['host-ip'], + ['host-mac'], + ['host-platform'], + ['os-name'], + ['host-family'], + ['host-version'], + ['host-architecture'], + undefined, // Max anomaly score by job doesn't implement getValues + ['cloud-provider'], + ['cloud-region'], + ['cloud-instance-id'], + ['cloud-machine-type'], + undefined, // Endpoint integration policy doesn't implement getValues + undefined, // Policy Status doesn't implement getValues + ['endpoint-agent-version'], + undefined, // Agent status doesn't implement getValues + ]); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/hooks/use_observed_host_fields.ts b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/hooks/use_observed_host_fields.ts new file mode 100644 index 0000000000000..255bb54c2c58a --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/hooks/use_observed_host_fields.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 { useMemo } from 'react'; +import { useMlCapabilities } from '../../../../common/components/ml/hooks/use_ml_capabilities'; +import type { HostItem } from '../../../../../common/search_strategy'; +import { getAnomaliesFields } from '../../shared/common'; +import type { EntityTableRows } from '../../shared/components/entity_table/types'; +import type { ObservedEntityData } from '../../shared/components/observed_entity/types'; +import { policyFields } from '../fields/endpoint_policy_fields'; +import { basicHostFields } from '../fields/basic_host_fields'; +import { cloudFields } from '../fields/cloud_fields'; + +export const useObservedHostFields = ( + hostData: ObservedEntityData +): EntityTableRows> => { + const mlCapabilities = useMlCapabilities(); + + return useMemo(() => { + if (hostData == null) { + return []; + } + + return [ + ...basicHostFields, + ...getAnomaliesFields(mlCapabilities), + ...cloudFields, + ...policyFields, + ]; + }, [hostData, mlCapabilities]); +}; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.test.tsx new file mode 100644 index 0000000000000..467a1be82a44c --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.test.tsx @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 '../../../common/mock'; +import { mockHostRiskScoreState, mockObservedHostData } from '../mocks'; + +import type { HostPanelProps } from '.'; +import { HostPanel } from '.'; + +const mockProps: HostPanelProps = { + hostName: 'test', + contextID: 'test-host -panel', + scopeId: 'test-scope-id', + isDraggable: false, +}; + +jest.mock('../../../common/components/visualization_actions/visualization_embeddable'); + +const mockedHostRiskScore = jest.fn().mockReturnValue(mockHostRiskScoreState); +jest.mock('../../../entity_analytics/api/hooks/use_risk_score', () => ({ + useRiskScore: () => mockedHostRiskScore(), +})); + +const mockedUseObservedHost = jest.fn().mockReturnValue(mockObservedHostData); + +jest.mock('./hooks/use_observed_host', () => ({ + useObservedHost: () => mockedUseObservedHost(), +})); + +describe('HostPanel', () => { + beforeEach(() => { + mockedHostRiskScore.mockReturnValue(mockHostRiskScoreState); + mockedUseObservedHost.mockReturnValue(mockObservedHostData); + }); + + it('renders', () => { + const { getByTestId, queryByTestId } = render( + + + + ); + + expect(getByTestId('host-panel-header')).toBeInTheDocument(); + expect(queryByTestId('securitySolutionFlyoutLoading')).not.toBeInTheDocument(); + expect(getByTestId('securitySolutionFlyoutNavigationExpandDetailButton')).toBeInTheDocument(); + }); + + it('renders loading state when risk score is loading', () => { + mockedHostRiskScore.mockReturnValue({ + ...mockHostRiskScoreState, + data: undefined, + loading: true, + }); + + const { getByTestId } = render( + + + + ); + + expect(getByTestId('securitySolutionFlyoutLoading')).toBeInTheDocument(); + }); + + it('renders loading state when observed host is loading', () => { + mockedUseObservedHost.mockReturnValue({ + ...mockObservedHostData, + isLoading: true, + }); + + const { getByTestId } = render( + + + + ); + + expect(getByTestId('securitySolutionFlyoutLoading')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.tsx new file mode 100644 index 0000000000000..783a9ce598381 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.tsx @@ -0,0 +1,141 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useMemo } from 'react'; +import type { FlyoutPanelProps } from '@kbn/expandable-flyout'; +import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; + +import { hostToCriteria } from '../../../common/components/ml/criteria/host_to_criteria'; +import { useRiskScore } from '../../../entity_analytics/api/hooks/use_risk_score'; +import { useQueryInspector } from '../../../common/components/page/manage_query'; +import { useGlobalTime } from '../../../common/containers/use_global_time'; +import type { HostItem } from '../../../../common/search_strategy'; +import { buildHostNamesFilter } from '../../../../common/search_strategy'; +import { RiskScoreEntity } from '../../../../common/entity_analytics/risk_engine'; +import { FlyoutLoading } from '../../shared/components/flyout_loading'; +import { FlyoutNavigation } from '../../shared/components/flyout_navigation'; +import { HostPanelContent } from './content'; +import { HostPanelHeader } from './header'; +import { AnomalyTableProvider } from '../../../common/components/ml/anomaly/anomaly_table_provider'; +import type { ObservedEntityData } from '../shared/components/observed_entity/types'; +import { useObservedHost } from './hooks/use_observed_host'; +import { HostDetailsPanelKey } from '../host_details_left'; +import type { EntityDetailsLeftPanelTab } from '../shared/components/left_panel/left_panel_header'; + +export interface HostPanelProps extends Record { + contextID: string; + scopeId: string; + hostName: string; + isDraggable?: boolean; +} + +export interface HostPanelExpandableFlyoutProps extends FlyoutPanelProps { + key: 'host-panel'; + params: HostPanelProps; +} + +export const HostPanelKey: HostPanelExpandableFlyoutProps['key'] = 'host-panel'; +export const HOST_PANEL_RISK_SCORE_QUERY_ID = 'HostPanelRiskScoreQuery'; +export const HOST_PANEL_OBSERVED_HOST_QUERY_ID = 'HostPanelObservedHostQuery'; + +const FIRST_RECORD_PAGINATION = { + cursorStart: 0, + querySize: 1, +}; + +export const HostPanel = ({ contextID, scopeId, hostName, isDraggable }: HostPanelProps) => { + const { openLeftPanel } = useExpandableFlyoutContext(); + const { to, from, isInitializing, setQuery, deleteQuery } = useGlobalTime(); + const hostNameFilterQuery = useMemo( + () => (hostName ? buildHostNamesFilter([hostName]) : undefined), + [hostName] + ); + + const riskScoreState = useRiskScore({ + riskEntity: RiskScoreEntity.host, + filterQuery: hostNameFilterQuery, + onlyLatest: false, + pagination: FIRST_RECORD_PAGINATION, + }); + + const { data: hostRisk, inspect: inspectRiskScore, refetch, loading } = riskScoreState; + const hostRiskData = hostRisk && hostRisk.length > 0 ? hostRisk[0] : undefined; + + useQueryInspector({ + deleteQuery, + inspect: inspectRiskScore, + loading, + queryId: HOST_PANEL_RISK_SCORE_QUERY_ID, + refetch, + setQuery, + }); + + const openTabPanel = useCallback( + (tab?: EntityDetailsLeftPanelTab) => { + openLeftPanel({ + id: HostDetailsPanelKey, + params: { + riskInputs: { + alertIds: hostRiskData?.host.risk.inputs?.map(({ id }) => id) ?? [], + host: { + name: hostName, + }, + }, + path: tab ? { tab } : undefined, + }, + }); + }, + [openLeftPanel, hostRiskData?.host.risk.inputs, hostName] + ); + + const openDefaultPanel = useCallback(() => openTabPanel(), [openTabPanel]); + const observedHost = useObservedHost(hostName); + + if (riskScoreState.loading || observedHost.isLoading) { + return ; + } + + return ( + + {({ isLoadingAnomaliesData, anomaliesData, jobNameById }) => { + const observedHostWithAnomalies: ObservedEntityData = { + ...observedHost, + anomalies: { + isLoading: isLoadingAnomaliesData, + anomalies: anomaliesData, + jobNameById, + }, + }; + + return ( + <> + + + + + ); + }} + + ); +}; + +HostPanel.displayName = 'HostPanel'; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/mocks/index.ts b/x-pack/plugins/security_solution/public/flyout/entity_details/mocks/index.ts new file mode 100644 index 0000000000000..01dafb9d6b47a --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/mocks/index.ts @@ -0,0 +1,168 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { HostMetadataInterface } from '../../../../common/endpoint/types'; +import { EndpointStatus, HostStatus } from '../../../../common/endpoint/types'; +import type { RiskScoreState } from '../../../entity_analytics/api/hooks/use_risk_score'; +import type { + HostItem, + HostRiskScore, + RiskScoreEntity, + UserRiskScore, +} from '../../../../common/search_strategy'; +import { HostPolicyResponseActionStatus, RiskSeverity } from '../../../../common/search_strategy'; +import { RiskCategories } from '../../../../common/entity_analytics/risk_engine'; +import type { ObservedEntityData } from '../shared/components/observed_entity/types'; + +const userRiskScore: UserRiskScore = { + '@timestamp': '1989-11-08T23:00:00.000Z', + user: { + name: 'test', + risk: { + rule_risks: [], + calculated_score_norm: 70, + multipliers: [], + calculated_level: RiskSeverity.high, + inputs: [ + { + id: '_id', + index: '_index', + category: RiskCategories.category_1, + description: 'Alert from Rule: My rule', + risk_score: 30, + timestamp: '2021-08-19T18:55:59.000Z', + }, + ], + }, + }, + alertsCount: 0, + oldestAlertTimestamp: '1989-11-08T23:00:00.000Z', +}; + +const hostRiskScore: HostRiskScore = { + '@timestamp': '1989-11-08T23:00:00.000Z', + host: { + name: 'test', + risk: { + rule_risks: [], + calculated_score_norm: 70, + multipliers: [], + calculated_level: RiskSeverity.high, + inputs: [ + { + id: '_id', + index: '_index', + category: RiskCategories.category_1, + description: 'Alert from Rule: My rule', + risk_score: 30, + timestamp: '2021-08-19T18:55:59.000Z', + }, + ], + }, + }, + alertsCount: 0, + oldestAlertTimestamp: '1989-11-08T23:00:00.000Z', +}; + +export const mockUserRiskScoreState: RiskScoreState = { + data: [userRiskScore], + inspect: { + dsl: [], + response: [], + }, + isInspected: false, + refetch: () => {}, + totalCount: 0, + isModuleEnabled: true, + isAuthorized: true, + isDeprecated: false, + loading: false, +}; + +export const mockHostRiskScoreState: RiskScoreState = { + data: [hostRiskScore], + inspect: { + dsl: [], + response: [], + }, + isInspected: false, + refetch: () => {}, + totalCount: 0, + isModuleEnabled: true, + isAuthorized: true, + isDeprecated: false, + loading: false, +}; + +const hostMetadata: HostMetadataInterface = { + '@timestamp': 1036358673463478, + + agent: { + id: 'endpoint-agent-id', + version: 'endpoint-agent-version', + type: 'endpoint-agent-type', + }, + Endpoint: { + status: EndpointStatus.enrolled, + policy: { + applied: { + name: 'policy-name', + id: 'C2A9093E-E289-4C0A-AA44-8C32A414FA7A', + endpoint_policy_version: 3, + version: 5, + status: HostPolicyResponseActionStatus.failure, + }, + }, + }, +} as HostMetadataInterface; + +export const mockObservedHost: HostItem = { + host: { + id: ['host-id'], + mac: ['host-mac'], + architecture: ['host-architecture'], + os: { + platform: ['host-platform'], + name: ['os-name'], + version: ['host-version'], + family: ['host-family'], + }, + ip: ['host-ip'], + name: ['host-name'], + }, + cloud: { + instance: { + id: ['cloud-instance-id'], + }, + provider: ['cloud-provider'], + region: ['cloud-region'], + machine: { + type: ['cloud-machine-type'], + }, + }, + endpoint: { + hostInfo: { + metadata: hostMetadata, + host_status: HostStatus.HEALTHY, + last_checkin: 'host-last-checkin', + }, + }, +}; + +export const mockObservedHostData: ObservedEntityData = { + details: mockObservedHost, + isLoading: false, + firstSeen: { + isLoading: false, + date: '2023-02-23T20:03:17.489Z', + }, + lastSeen: { + isLoading: false, + date: '2023-02-23T20:03:17.489Z', + }, + anomalies: { isLoading: false, anomalies: null, jobNameById: {} }, +}; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/common.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/common.test.tsx new file mode 100644 index 0000000000000..70b37fd8ba722 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/common.test.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getAnomaliesFields } from './common'; +import { emptyMlCapabilities } from '../../../../common/machine_learning/empty_ml_capabilities'; + +const emptyMlCapabilitiesProvider = { + ...emptyMlCapabilities, + capabilitiesFetched: false, +}; + +describe('getAnomaliesFields', () => { + it('returns max anomaly score', () => { + const field = getAnomaliesFields(emptyMlCapabilitiesProvider); + + expect(field[0].label).toBe('Max anomaly score by job'); + }); + + it('hides anomalies field when user has no permissions', () => { + const field = getAnomaliesFields(emptyMlCapabilitiesProvider); + + expect(field[0].isVisible()).toBeFalsy(); + }); + + it('shows anomalies field when user has permissions', () => { + const mlCapabilitiesProvider = { + ...emptyMlCapabilities, + capabilitiesFetched: false, + capabilities: { + ...emptyMlCapabilities.capabilities, + canGetJobs: true, + canGetDatafeeds: true, + canGetCalendars: true, + }, + }; + + const field = getAnomaliesFields(mlCapabilitiesProvider); + + expect(field[0].isVisible()).toBeTruthy(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/common.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/common.tsx new file mode 100644 index 0000000000000..95d4758c2c449 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/common.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 { i18n } from '@kbn/i18n'; +import type { ObservedEntityData } from './components/observed_entity/types'; +import type { MlCapabilitiesProvider } from '../../../common/components/ml/permissions/ml_capabilities_provider'; +import { hasMlUserPermissions } from '../../../../common/machine_learning/has_ml_user_permissions'; +import { getEmptyTagValue } from '../../../common/components/empty_value'; +import type { HostItem } from '../../../../common/search_strategy'; +import { AnomaliesField } from './components/anomalies_field'; + +export const getAnomaliesFields = (mlCapabilities: MlCapabilitiesProvider) => [ + { + label: i18n.translate('xpack.securitySolution.timeline.sidePanel.maxAnomalyScoreByJobTitle', { + defaultMessage: 'Max anomaly score by job', + }), + render: (hostData: ObservedEntityData) => + hostData.anomalies ? : getEmptyTagValue(), + isVisible: () => hasMlUserPermissions(mlCapabilities), + }, +]; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/anomalies_field.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/anomalies_field.test.tsx new file mode 100644 index 0000000000000..c8a2cdbb71dae --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/anomalies_field.test.tsx @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { mockAnomalies } from '../../../../common/components/ml/mock'; +import { render } from '@testing-library/react'; +import React from 'react'; +import { AnomaliesField } from './anomalies_field'; +import { TestProviders } from '../../../../common/mock'; + +jest.mock('../../../../common/components/cell_actions', () => { + const actual = jest.requireActual('../../../../common/components/cell_actions'); + return { + ...actual, + SecurityCellActions: () => <>, + }; +}); + +describe('getAnomaliesFields', () => { + it('returns max anomaly score', () => { + const { getByTestId } = render( + , + { + wrapper: TestProviders, + } + ); + + expect(getByTestId('anomaly-scores')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/anomalies_field.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/anomalies_field.tsx new file mode 100644 index 0000000000000..ea5e7b17202f0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/anomalies_field.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback } from 'react'; +import { useDispatch } from 'react-redux'; +import type { EntityAnomalies } from './observed_entity/types'; +import { AnomalyScores } from '../../../../common/components/ml/score/anomaly_scores'; +import { useGlobalTime } from '../../../../common/containers/use_global_time'; +import { scoreIntervalToDateTime } from '../../../../common/components/ml/score/score_interval_to_datetime'; +import { InputsModelId } from '../../../../common/store/inputs/constants'; +import { setAbsoluteRangeDatePicker } from '../../../../common/store/inputs/actions'; + +export const AnomaliesField = ({ anomalies }: { anomalies: EntityAnomalies }) => { + const { to, from } = useGlobalTime(); + const dispatch = useDispatch(); + + const narrowDateRange = useCallback( + (score, interval) => { + const fromTo = scoreIntervalToDateTime(score, interval); + dispatch( + setAbsoluteRangeDatePicker({ + id: InputsModelId.global, + from: fromTo.from, + to: fromTo.to, + }) + ); + }, + [dispatch] + ); + + return ( + + ); +}; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/entity_table/columns.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/entity_table/columns.tsx new file mode 100644 index 0000000000000..e97ab9b4accae --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/entity_table/columns.tsx @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { css } from '@emotion/react'; +import React from 'react'; +import { euiLightVars } from '@kbn/ui-theme'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { DefaultFieldRenderer } from '../../../../../timelines/components/field_renderers/field_renderers'; +import { getEmptyTagValue } from '../../../../../common/components/empty_value'; +import { getSourcererScopeId } from '../../../../../helpers'; +import type { BasicEntityData, EntityTableColumns } from './types'; + +export const getEntityTableColumns = ( + contextID: string, + scopeId: string, + isDraggable: boolean, + data: T +): EntityTableColumns => [ + { + name: ( + + ), + field: 'label', + render: (label: string, { field }) => ( + + {label ?? field} + + ), + }, + { + name: ( + + ), + field: 'field', + render: (field: string | undefined, { getValues, render, renderField }) => { + const values = getValues && getValues(data); + + if (field) { + return ( + + ); + } + + if (render) { + return render(data); + } + + return getEmptyTagValue(); + }, + }, +]; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/entity_table/index.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/entity_table/index.test.tsx new file mode 100644 index 0000000000000..d6243abb39e9f --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/entity_table/index.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 { render } from '@testing-library/react'; +import React from 'react'; +import { EntityTable } from '.'; +import { TestProviders } from '../../../../../common/mock'; +import type { BasicEntityData, EntityTableRow } from './types'; + +const renderedFieldValue = 'testValue1'; + +const testField: EntityTableRow = { + label: 'testLabel', + field: 'testField', + getValues: (data: unknown) => [renderedFieldValue], + renderField: (field: string) => <>{field}, +}; + +const mockProps = { + contextID: 'testContextID', + scopeId: 'testScopeId', + isDraggable: false, + data: { isLoading: false }, + entityFields: [testField], +}; + +describe('EntityTable', () => { + it('renders correctly', () => { + const { queryByTestId, queryAllByTestId } = render(, { + wrapper: TestProviders, + }); + + expect(queryByTestId('entity-table')).toBeInTheDocument(); + expect(queryAllByTestId('entity-table-label')).toHaveLength(1); + }); + + it("it doesn't render fields when isVisible returns false", () => { + const props = { + ...mockProps, + entityFields: [ + { + ...testField, + isVisible: () => false, + }, + ], + }; + + const { queryAllByTestId } = render(, { + wrapper: TestProviders, + }); + + expect(queryAllByTestId('entity-table-label')).toHaveLength(0); + }); + + it('it renders the field label', () => { + const { queryByTestId } = render(, { + wrapper: TestProviders, + }); + + expect(queryByTestId('entity-table-label')).toHaveTextContent('testLabel'); + }); + + it('it renders the field value', () => { + const { queryByTestId } = render(, { + wrapper: TestProviders, + }); + + expect(queryByTestId('DefaultFieldRendererComponent')).toHaveTextContent(renderedFieldValue); + }); + + it('it call render function when field is undefined', () => { + const props = { + ...mockProps, + entityFields: [ + { + label: 'testLabel', + render: (data: unknown) => ( + {'test-custom-render'} + ), + }, + ], + }; + + const { queryByTestId } = render(, { + wrapper: TestProviders, + }); + + expect(queryByTestId('test-custom-render')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/entity_table/index.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/entity_table/index.tsx new file mode 100644 index 0000000000000..84075071e7a9f --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/entity_table/index.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import { BasicTable } from '../../../../../common/components/ml/tables/basic_table'; +import { getEntityTableColumns } from './columns'; +import type { BasicEntityData, EntityTableRows } from './types'; + +interface EntityTableProps { + contextID: string; + scopeId: string; + isDraggable: boolean; + data: T; + entityFields: EntityTableRows; +} + +export const EntityTable = ({ + contextID, + scopeId, + isDraggable, + data, + entityFields, +}: EntityTableProps) => { + const items = useMemo( + () => entityFields.filter(({ isVisible }) => (isVisible ? isVisible(data) : true)), + [data, entityFields] + ); + + const entityTableColumns = useMemo( + () => getEntityTableColumns(contextID, scopeId, isDraggable, data), + [contextID, scopeId, isDraggable, data] + ); + return ( + + ); +}; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/entity_table/types.ts b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/entity_table/types.ts new file mode 100644 index 0000000000000..690a99ec92ce3 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/entity_table/types.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { EuiBasicTableColumn } from '@elastic/eui'; +import type { XOR } from '../../../../../../common/utility_types'; + +export type EntityTableRow = XOR< + { + label: string; + /** + * The field name. It is used for displaying CellActions. + */ + field: string; + /** + * It extracts an array of strings from the data. Each element is a valid field value. + * It is used for displaying MoreContainer. + */ + getValues: (data: T) => string[] | null | undefined; + /** + * It allows the customization of the rendered field. + * The element is still rendered inside `DefaultFieldRenderer` getting `CellActions` and `MoreContainer` capabilities. + */ + renderField?: (value: string) => JSX.Element; + /** + * It hides the row when `isVisible` returns false. + */ + isVisible?: (data: T) => boolean; + }, + { + label: string; + /** + * It takes complete control over the rendering. + * `getValues` and `renderField` are not called when this property is used. + */ + render: (data: T) => JSX.Element; + /** + * It hides the row when `isVisible` returns false. + */ + isVisible?: (data: T) => boolean; + } +>; + +export type EntityTableColumns = Array< + EuiBasicTableColumn> +>; +export type EntityTableRows = Array>; + +export interface BasicEntityData { + isLoading: boolean; +} diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/content.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_content.tsx similarity index 70% rename from x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/content.tsx rename to x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_content.tsx index 991592bd1ea0c..5a66a5b305611 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/content.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_content.tsx @@ -9,19 +9,19 @@ import { useEuiBackgroundColor } from '@elastic/eui'; import type { VFC } from 'react'; import React, { useMemo } from 'react'; import { css } from '@emotion/react'; -import type { LeftPanelTabsType, UserDetailsLeftPanelTab } from './tabs'; -import { FlyoutBody } from '../../shared/components/flyout_body'; +import { FlyoutBody } from '../../../../shared/components/flyout_body'; +import type { EntityDetailsLeftPanelTab, LeftPanelTabsType } from './left_panel_header'; export interface PanelContentProps { - selectedTabId: UserDetailsLeftPanelTab; + selectedTabId: EntityDetailsLeftPanelTab; tabs: LeftPanelTabsType; } /** - * User details expandable flyout left section. + * Content for a entity left panel. * Appears after the user clicks on the expand details button in the right section. */ -export const PanelContent: VFC = ({ selectedTabId, tabs }) => { +export const LeftPanelContent: VFC = ({ selectedTabId, tabs }) => { const selectedTabContent = useMemo(() => { return tabs.find((tab) => tab.id === selectedTabId)?.content; }, [selectedTabId, tabs]); @@ -37,4 +37,4 @@ export const PanelContent: VFC = ({ selectedTabId, tabs }) => ); }; -PanelContent.displayName = 'PanelContent'; +LeftPanelContent.displayName = 'LeftPanelContent'; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/header.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_header.tsx similarity index 67% rename from x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/header.tsx rename to x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_header.tsx index 2f807ca1d0a7d..ea62ce25f3ca4 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/header.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_header.tsx @@ -6,21 +6,33 @@ */ import { EuiTab, EuiTabs, useEuiBackgroundColor } from '@elastic/eui'; -import type { VFC } from 'react'; +import type { ReactElement, VFC } from 'react'; import React, { memo } from 'react'; import { css } from '@emotion/react'; -import type { LeftPanelTabsType, UserDetailsLeftPanelTab } from './tabs'; -import { FlyoutHeader } from '../../shared/components/flyout_header'; +import { FlyoutHeader } from '../../../../shared/components/flyout_header'; + +export type LeftPanelTabsType = Array<{ + id: EntityDetailsLeftPanelTab; + 'data-test-subj': string; + name: ReactElement; + content: React.ReactElement; +}>; + +export enum EntityDetailsLeftPanelTab { + RISK_INPUTS = 'risk_inputs', + OKTA = 'okta_document', + ENTRA = 'entra_document', +} export interface PanelHeaderProps { /** * Id of the tab selected in the parent component to display its content */ - selectedTabId: UserDetailsLeftPanelTab; + selectedTabId: EntityDetailsLeftPanelTab; /** * Callback to set the selected tab id in the parent component */ - setSelectedTabId: (selected: UserDetailsLeftPanelTab) => void; + setSelectedTabId: (selected: EntityDetailsLeftPanelTab) => void; /** * List of tabs to display in the header */ @@ -31,9 +43,9 @@ export interface PanelHeaderProps { * Header at the top of the left section. * Displays the investigation and insights tabs (visualize is hidden for 8.9). */ -export const PanelHeader: VFC = memo( +export const LeftPanelHeader: VFC = memo( ({ selectedTabId, setSelectedTabId, tabs }) => { - const onSelectedTabChanged = (id: UserDetailsLeftPanelTab) => setSelectedTabId(id); + const onSelectedTabChanged = (id: EntityDetailsLeftPanelTab) => setSelectedTabId(id); const renderTabs = tabs.map((tab, index) => ( onSelectedTabChanged(tab.id)} @@ -61,4 +73,4 @@ export const PanelHeader: VFC = memo( } ); -PanelHeader.displayName = 'PanelHeader'; +LeftPanelHeader.displayName = 'LeftPanelHeader'; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/observed_entity/index.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/observed_entity/index.test.tsx new file mode 100644 index 0000000000000..f3cdfefa6c74f --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/observed_entity/index.test.tsx @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { render } from '@testing-library/react'; +import React from 'react'; +import { ObservedEntity } from '.'; +import { TestProviders } from '../../../../../common/mock'; +import { mockObservedHostData } from '../../../mocks'; + +describe('ObservedHost', () => { + const mockProps = { + observedData: mockObservedHostData, + contextID: '', + scopeId: '', + isDraggable: false, + queryId: 'TEST_QUERY_ID', + observedFields: [], + }; + + it('renders', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('observedEntity-accordion')).toBeInTheDocument(); + }); + + it('renders the formatted date', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('observedEntity-accordion')).toHaveTextContent('Updated Feb 23, 2023'); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/observed_user.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/observed_entity/index.tsx similarity index 51% rename from x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/observed_user.tsx rename to x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/observed_entity/index.tsx index 411e516b570f3..792ad322e631b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/observed_user.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/observed_entity/index.tsx @@ -5,39 +5,34 @@ * 2.0. */ -import { EuiAccordion, EuiSpacer, EuiTitle, useEuiTheme, useEuiFontSize } from '@elastic/eui'; +import { EuiAccordion, EuiSpacer, EuiTitle, useEuiFontSize, useEuiTheme } from '@elastic/eui'; -import React, { useMemo } from 'react'; +import React from 'react'; import { css } from '@emotion/react'; import { FormattedMessage } from '@kbn/i18n-react'; -import * as i18n from './translations'; -import type { ObservedUserData } from './types'; -import { BasicTable } from '../../../../common/components/ml/tables/basic_table'; -import { FormattedRelativePreferenceDate } from '../../../../common/components/formatted_date'; -import { getObservedUserTableColumns } from './columns'; -import { ONE_WEEK_IN_HOURS } from './constants'; -import { InspectButton, InspectButtonContainer } from '../../../../common/components/inspect'; -import { OBSERVED_USER_QUERY_ID } from '../../../../explore/users/containers/users/observed_details'; -import { useObservedUserItems } from './hooks/use_observed_user_items'; +import { EntityTable } from '../entity_table'; +import { FormattedRelativePreferenceDate } from '../../../../../common/components/formatted_date'; +import { InspectButton, InspectButtonContainer } from '../../../../../common/components/inspect'; +import type { EntityTableRows } from '../entity_table/types'; +import { ONE_WEEK_IN_HOURS } from '../../constants'; +import type { ObservedEntityData } from './types'; -export const ObservedUser = ({ - observedUser, +export const ObservedEntity = ({ + observedData, contextID, scopeId, isDraggable, + observedFields, + queryId, }: { - observedUser: ObservedUserData; + observedData: ObservedEntityData; contextID: string; scopeId: string; isDraggable: boolean; + observedFields: EntityTableRows>; + queryId: string; }) => { const { euiTheme } = useEuiTheme(); - const observedItems = useObservedUserItems(observedUser); - - const observedUserTableColumns = useMemo( - () => getObservedUserTableColumns(contextID, scopeId, isDraggable), - [contextID, scopeId, isDraggable] - ); const xsFontSize = useEuiFontSize('xxs').fontSize; return ( @@ -45,18 +40,23 @@ export const ObservedUser = ({ -

{i18n.OBSERVED_DATA_TITLE}

+

+ +

} extraAction={ @@ -67,23 +67,28 @@ export const ObservedUser = ({ `} > + } /> - {observedUser.lastSeen.date && ( + {observedData.lastSeen.date && ( @@ -101,17 +106,12 @@ export const ObservedUser = ({ `} > - -
diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/observed_entity/types.ts b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/observed_entity/types.ts new file mode 100644 index 0000000000000..f9d9db179d3f6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/observed_entity/types.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { BasicEntityData } from '../entity_table/types'; +import type { AnomalyTableProviderChildrenProps } from '../../../../../common/components/ml/anomaly/anomaly_table_provider'; + +export interface FirstLastSeenData { + date: string | null | undefined; + isLoading: boolean; +} + +export interface EntityAnomalies { + isLoading: AnomalyTableProviderChildrenProps['isLoadingAnomaliesData']; + anomalies: AnomalyTableProviderChildrenProps['anomaliesData']; + jobNameById: AnomalyTableProviderChildrenProps['jobNameById']; +} + +export interface ObservedEntityData extends BasicEntityData { + firstSeen: FirstLastSeenData; + lastSeen: FirstLastSeenData; + anomalies: EntityAnomalies; + details: T; +} diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/constants.ts b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/constants.ts new file mode 100644 index 0000000000000..bad35d3657891 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/constants.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 const ONE_WEEK_IN_HOURS = 24 * 7; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/index.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/index.tsx index ae96a76c68d4e..c2591eab2c914 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/index.tsx @@ -9,11 +9,14 @@ import React, { useMemo } from 'react'; import type { FlyoutPanelProps, PanelPath } from '@kbn/expandable-flyout'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; import { useManagedUser } from '../../../timelines/components/side_panel/new_user_detail/hooks/use_managed_user'; -import { PanelHeader } from './header'; -import { PanelContent } from './content'; -import type { LeftPanelTabsType, UserDetailsLeftPanelTab } from './tabs'; import { useTabs } from './tabs'; import { FlyoutLoading } from '../../shared/components/flyout_loading'; +import type { + EntityDetailsLeftPanelTab, + LeftPanelTabsType, +} from '../shared/components/left_panel/left_panel_header'; +import { LeftPanelHeader } from '../shared/components/left_panel/left_panel_header'; +import { LeftPanelContent } from '../shared/components/left_panel/left_panel_content'; interface RiskInputsParam { alertIds: string[]; @@ -44,8 +47,12 @@ export const UserDetailsPanel = ({ riskInputs, user, path }: UserDetailsPanelPro return ( <> - - + + ); }; @@ -65,7 +72,7 @@ const useSelectedTab = ( return tabs.find((tab) => tab.id === path.tab)?.id ?? defaultTab; }, [path, tabs]); - const setSelectedTabId = (tabId: UserDetailsLeftPanelTab) => { + const setSelectedTabId = (tabId: EntityDetailsLeftPanelTab) => { openLeftPanel({ id: UserDetailsPanelKey, path: { diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/tabs.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/tabs.tsx index 61f408a5c0ade..3867afb4470e2 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/tabs.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/tabs.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import type { ReactElement } from 'react'; import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -19,19 +18,8 @@ import type { import { ENTRA_TAB_TEST_ID, OKTA_TAB_TEST_ID } from './test_ids'; import { AssetDocumentTab } from './tabs/asset_document'; import { RightPanelProvider } from '../../document_details/right/context'; - -export type LeftPanelTabsType = Array<{ - id: UserDetailsLeftPanelTab; - 'data-test-subj': string; - name: ReactElement; - content: React.ReactElement; -}>; - -export enum UserDetailsLeftPanelTab { - RISK_INPUTS = 'risk_inputs', - OKTA = 'okta_document', - ENTRA = 'entra_document', -} +import type { LeftPanelTabsType } from '../shared/components/left_panel/left_panel_header'; +import { EntityDetailsLeftPanelTab } from '../shared/components/left_panel/left_panel_header'; export const useTabs = (managedUser: ManagedUserHits, alertIds: string[]): LeftPanelTabsType => useMemo(() => { @@ -55,7 +43,7 @@ export const useTabs = (managedUser: ManagedUserHits, alertIds: string[]): LeftP }, [alertIds, managedUser]); const getOktaTab = (oktaManagedUser: ManagedUserHit) => ({ - id: UserDetailsLeftPanelTab.OKTA, + id: EntityDetailsLeftPanelTab.OKTA, 'data-test-subj': OKTA_TAB_TEST_ID, name: ( ({ const getEntraTab = (entraManagedUser: ManagedUserHit) => { return { - id: UserDetailsLeftPanelTab.ENTRA, + id: EntityDetailsLeftPanelTab.ENTRA, 'data-test-subj': ENTRA_TAB_TEST_ID, name: ( window.alert('openLeftPanel called'), diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx index 9b99c42aeac7a..f1f7916d3907c 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx @@ -8,27 +8,27 @@ import { EuiHorizontalRule } from '@elastic/eui'; import React from 'react'; +import { OBSERVED_USER_QUERY_ID } from '../../../explore/users/containers/users/observed_details'; import { RiskSummary } from '../../../entity_analytics/components/risk_summary_flyout/risk_summary'; import type { RiskScoreState } from '../../../entity_analytics/api/hooks/use_risk_score'; import { ManagedUser } from '../../../timelines/components/side_panel/new_user_detail/managed_user'; -import type { - ManagedUserData, - ObservedUserData, -} from '../../../timelines/components/side_panel/new_user_detail/types'; -import { ObservedUser } from '../../../timelines/components/side_panel/new_user_detail/observed_user'; -import type { RiskScoreEntity } from '../../../../common/search_strategy'; +import type { ManagedUserData } from '../../../timelines/components/side_panel/new_user_detail/types'; +import type { RiskScoreEntity, UserItem } from '../../../../common/search_strategy'; import { USER_PANEL_RISK_SCORE_QUERY_ID } from '.'; import { FlyoutBody } from '../../shared/components/flyout_body'; -import type { UserDetailsLeftPanelTab } from '../user_details_left/tabs'; +import { ObservedEntity } from '../shared/components/observed_entity'; +import type { ObservedEntityData } from '../shared/components/observed_entity/types'; +import { useObservedUserItems } from './hooks/use_observed_user_items'; +import type { EntityDetailsLeftPanelTab } from '../shared/components/left_panel/left_panel_header'; interface UserPanelContentProps { - observedUser: ObservedUserData; + observedUser: ObservedEntityData; managedUser: ManagedUserData; riskScoreState: RiskScoreState; contextID: string; scopeId: string; isDraggable: boolean; - openDetailsPanel: (tab: UserDetailsLeftPanelTab) => void; + openDetailsPanel: (tab: EntityDetailsLeftPanelTab) => void; } export const UserPanelContent = ({ @@ -40,6 +40,8 @@ export const UserPanelContent = ({ isDraggable, openDetailsPanel, }: UserPanelContentProps) => { + const observedFields = useObservedUserItems(observedUser); + return ( {riskScoreState.isModuleEnabled && riskScoreState.data?.length !== 0 && ( @@ -52,11 +54,13 @@ export const UserPanelContent = ({ )} - ; managedUser: ManagedUserData; } diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/hooks/translations.ts b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/hooks/translations.ts new file mode 100644 index 0000000000000..9c7637d75f543 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/hooks/translations.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 { i18n } from '@kbn/i18n'; + +export const USER_ID = i18n.translate('xpack.securitySolution.flyout.entityDetails.user.idLabel', { + defaultMessage: 'User ID', +}); + +export const MAX_ANOMALY_SCORE_BY_JOB = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.user.maxAnomalyScoreByJobLabel', + { + defaultMessage: 'Max anomaly score by job', + } +); + +export const FIRST_SEEN = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.user.firstSeenLabel', + { + defaultMessage: 'First seen', + } +); + +export const LAST_SEEN = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.user.lastSeenLabel', + { + defaultMessage: 'Last seen', + } +); + +export const OPERATING_SYSTEM_TITLE = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.user.hostOsNameLabel', + { + defaultMessage: 'Operating system', + } +); + +export const FAMILY = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.user.familyLabel', + { + defaultMessage: 'Family', + } +); + +export const IP_ADDRESSES = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.user.ipAddressesLabel', + { + defaultMessage: 'IP addresses', + } +); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/hooks/use_observed_user.ts b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/hooks/use_observed_user.ts similarity index 65% rename from x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/hooks/use_observed_user.ts rename to x-pack/plugins/security_solution/public/flyout/entity_details/user_right/hooks/use_observed_user.ts index d3d2c4fde90a1..6d1ae0ab11e00 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/hooks/use_observed_user.ts +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/hooks/use_observed_user.ts @@ -6,28 +6,18 @@ */ import { useMemo } from 'react'; -import { useObservedUserDetails } from '../../../../../explore/users/containers/users/observed_details'; -import type { UserItem } from '../../../../../../common/search_strategy'; -import { Direction, NOT_EVENT_KIND_ASSET_FILTER } from '../../../../../../common/search_strategy'; -import { useSourcererDataView } from '../../../../../common/containers/sourcerer'; -import { useGlobalTime } from '../../../../../common/containers/use_global_time'; -import { useFirstLastSeen } from '../../../../../common/containers/use_first_last_seen'; -import { useQueryInspector } from '../../../../../common/components/page/manage_query'; +import { useQueryInspector } from '../../../../common/components/page/manage_query'; +import type { ObservedEntityData } from '../../shared/components/observed_entity/types'; +import { useObservedUserDetails } from '../../../../explore/users/containers/users/observed_details'; +import type { UserItem } from '../../../../../common/search_strategy'; +import { Direction, NOT_EVENT_KIND_ASSET_FILTER } from '../../../../../common/search_strategy'; +import { useSourcererDataView } from '../../../../common/containers/sourcerer'; +import { useGlobalTime } from '../../../../common/containers/use_global_time'; +import { useFirstLastSeen } from '../../../../common/containers/use_first_last_seen'; -export interface ObserverUser { - details: UserItem; - isLoading: boolean; - firstSeen: { - date: string | null | undefined; - isLoading: boolean; - }; - lastSeen: { - date: string | null | undefined; - isLoading: boolean; - }; -} - -export const useObservedUser = (userName: string): ObserverUser => { +export const useObservedUser = ( + userName: string +): Omit, 'anomalies'> => { const { selectedPatterns } = useSourcererDataView(); const { to, from, isInitializing, deleteQuery, setQuery } = useGlobalTime(); @@ -68,7 +58,7 @@ export const useObservedUser = (userName: string): ObserverUser => { return useMemo( () => ({ details: observedUserDetails, - isLoading: loadingObservedUser, + isLoading: loadingObservedUser || loadingLastSeen || loadingFirstSeen, firstSeen: { date: firstSeen, isLoading: loadingFirstSeen, diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/hooks/use_observed_user_items.test.ts b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/hooks/use_observed_user_items.test.ts similarity index 53% rename from x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/hooks/use_observed_user_items.test.ts rename to x-pack/plugins/security_solution/public/flyout/entity_details/user_right/hooks/use_observed_user_items.test.ts index 40fd3c6089039..1c7b5557dd90a 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/hooks/use_observed_user_items.test.ts +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/hooks/use_observed_user_items.test.ts @@ -5,13 +5,13 @@ * 2.0. */ +import { TestProviders } from '@kbn/timelines-plugin/public/mock'; import { renderHook } from '@testing-library/react-hooks'; -import { TestProviders } from '../../../../../common/mock'; -import { mockObservedUser } from '../__mocks__'; +import { mockObservedUser } from '../mocks'; import { useObservedUserItems } from './use_observed_user_items'; describe('useManagedUserItems', () => { - it('returns managed user items for Entra user', () => { + it('returns observed user fields', () => { const { result } = renderHook(() => useObservedUserItems(mockObservedUser), { wrapper: TestProviders, }); @@ -20,43 +20,58 @@ describe('useManagedUserItems', () => { { field: 'user.id', label: 'User ID', - values: ['1234', '321'], + getValues: expect.any(Function), }, { field: 'user.domain', label: 'Domain', - values: ['test domain', 'another test domain'], - }, - { - field: 'anomalies', - label: 'Max anomaly score by job', - values: mockObservedUser.anomalies, + getValues: expect.any(Function), }, { field: '@timestamp', label: 'First seen', - values: ['2023-02-23T20:03:17.489Z'], + getValues: expect.any(Function), }, { field: '@timestamp', label: 'Last seen', - values: ['2023-02-23T20:03:17.489Z'], + getValues: expect.any(Function), }, { field: 'host.os.name', label: 'Operating system', - values: ['testOs'], + getValues: expect.any(Function), }, { field: 'host.os.family', label: 'Family', - values: ['testFamily'], + + getValues: expect.any(Function), }, { field: 'host.ip', label: 'IP addresses', - values: ['10.0.0.1', '127.0.0.1'], + + getValues: expect.any(Function), + }, + { + label: 'Max anomaly score by job', + isVisible: expect.any(Function), + render: expect.any(Function), }, ]); + + expect(result.current.map(({ getValues }) => getValues && getValues(mockObservedUser))).toEqual( + [ + ['1234', '321'], // id + ['test domain', 'another test domain'], // domain + ['2023-02-23T20:03:17.489Z'], // First seen + ['2023-02-23T20:03:17.489Z'], // Last seen + ['testOs'], // OS name + ['testFamily'], // os family + ['10.0.0.1', '127.0.0.1'], // IP addresses + undefined, // Max anomaly score by job doesn't implement getValues + ] + ); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/hooks/use_observed_user_items.ts b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/hooks/use_observed_user_items.ts new file mode 100644 index 0000000000000..7275b2ca55570 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/hooks/use_observed_user_items.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useMemo } from 'react'; +import type { UserItem } from '../../../../../common/search_strategy'; +import { useMlCapabilities } from '../../../../common/components/ml/hooks/use_ml_capabilities'; +import { getAnomaliesFields } from '../../shared/common'; +import * as i18n from './translations'; +import type { ObservedEntityData } from '../../shared/components/observed_entity/types'; +import type { EntityTableRows } from '../../shared/components/entity_table/types'; + +const basicUserFields: EntityTableRows> = [ + { + label: i18n.USER_ID, + getValues: (userData: ObservedEntityData) => userData.details.user?.id, + field: 'user.id', + }, + { + label: 'Domain', + getValues: (userData: ObservedEntityData) => userData.details.user?.domain, + field: 'user.domain', + }, + { + label: i18n.FIRST_SEEN, + getValues: (userData: ObservedEntityData) => + userData.firstSeen.date ? [userData.firstSeen.date] : undefined, + field: '@timestamp', + }, + { + label: i18n.LAST_SEEN, + getValues: (userData: ObservedEntityData) => + userData.lastSeen.date ? [userData.lastSeen.date] : undefined, + field: '@timestamp', + }, + { + label: i18n.OPERATING_SYSTEM_TITLE, + getValues: (userData: ObservedEntityData) => userData.details.host?.os?.name, + field: 'host.os.name', + }, + { + label: i18n.FAMILY, + getValues: (userData: ObservedEntityData) => userData.details.host?.os?.family, + field: 'host.os.family', + }, + { + label: i18n.IP_ADDRESSES, + getValues: (userData: ObservedEntityData) => userData.details.host?.ip, + field: 'host.ip', + }, +]; + +export const useObservedUserItems = ( + userData: ObservedEntityData +): EntityTableRows> => { + const mlCapabilities = useMlCapabilities(); + + const fields: EntityTableRows> = useMemo( + () => [...basicUserFields, ...getAnomaliesFields(mlCapabilities)], + [mlCapabilities] + ); + + if (!userData.details) { + return []; + } + + return fields; +}; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.test.tsx index 1c74e4ed23ea5..9961b3ea086e2 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.test.tsx @@ -10,12 +10,12 @@ import React from 'react'; import { TestProviders } from '../../../common/mock'; import type { UserPanelProps } from '.'; import { UserPanel } from '.'; -import { mockRiskScoreState } from './mocks'; import { mockManagedUserData, - mockObservedUser, + mockRiskScoreState, } from '../../../timelines/components/side_panel/new_user_detail/__mocks__'; +import { mockObservedUser } from './mocks'; const mockProps: UserPanelProps = { userName: 'test', @@ -41,12 +41,9 @@ jest.mock( }) ); -jest.mock( - '../../../timelines/components/side_panel/new_user_detail/hooks/use_observed_user', - () => ({ - useObservedUser: () => mockedUseObservedUser(), - }) -); +jest.mock('./hooks/use_observed_user', () => ({ + useObservedUser: () => mockedUseObservedUser(), +})); describe('UserPanel', () => { beforeEach(() => { diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx index 76168bc01c842..abe3ee4793016 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx @@ -11,7 +11,6 @@ import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; import { useRiskScore } from '../../../entity_analytics/api/hooks/use_risk_score'; import { ManagedUserDatasetKey } from '../../../../common/search_strategy/security_solution/users/managed_details'; import { useManagedUser } from '../../../timelines/components/side_panel/new_user_detail/hooks/use_managed_user'; -import { useObservedUser } from '../../../timelines/components/side_panel/new_user_detail/hooks/use_observed_user'; import { useQueryInspector } from '../../../common/components/page/manage_query'; import { UsersType } from '../../../explore/users/store/model'; import { getCriteriaFromUsersType } from '../../../common/components/ml/criteria/get_criteria_from_users_type'; @@ -24,7 +23,8 @@ import { FlyoutNavigation } from '../../shared/components/flyout_navigation'; import { UserPanelContent } from './content'; import { UserPanelHeader } from './header'; import { UserDetailsPanelKey } from '../user_details_left'; -import type { UserDetailsLeftPanelTab } from '../user_details_left/tabs'; +import { useObservedUser } from './hooks/use_observed_user'; +import type { EntityDetailsLeftPanelTab } from '../shared/components/left_panel/left_panel_header'; export interface UserPanelProps extends Record { contextID: string; @@ -79,7 +79,7 @@ export const UserPanel = ({ contextID, scopeId, userName, isDraggable }: UserPan const { openLeftPanel } = useExpandableFlyoutContext(); const openPanelTab = useCallback( - (tab?: UserDetailsLeftPanelTab) => { + (tab?: EntityDetailsLeftPanelTab) => { openLeftPanel({ id: UserDetailsPanelKey, params: { diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/mocks/index.ts b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/mocks/index.ts index 88ab3c10241cb..b58c94c5772ff 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/mocks/index.ts +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/mocks/index.ts @@ -5,47 +5,43 @@ * 2.0. */ -import type { RiskScoreState } from '../../../../entity_analytics/api/hooks/use_risk_score'; -import type { RiskScoreEntity, UserRiskScore } from '../../../../../common/search_strategy'; -import { RiskSeverity } from '../../../../../common/search_strategy'; -import { RiskCategories } from '../../../../../common/entity_analytics/risk_engine'; +import { mockAnomalies } from '../../../../common/components/ml/mock'; +import type { UserItem } from '../../../../../common/search_strategy'; +import type { ObservedEntityData } from '../../shared/components/observed_entity/types'; -const userRiskScore: UserRiskScore = { - '@timestamp': '626569200000', +const anomaly = mockAnomalies.anomalies[0]; + +const observedUserDetails = { user: { - name: 'test', - risk: { - rule_risks: [], - calculated_score_norm: 70, - multipliers: [], - calculated_level: RiskSeverity.high, - inputs: [ - { - id: '_id', - index: '_index', - category: RiskCategories.category_1, - description: 'Alert from Rule: My rule', - risk_score: 30, - timestamp: '2021-08-19T18:55:59.000Z', - }, - ], + id: ['1234', '321'], + domain: ['test domain', 'another test domain'], + }, + host: { + ip: ['10.0.0.1', '127.0.0.1'], + os: { + name: ['testOs'], + family: ['testFamily'], }, }, - alertsCount: 0, - oldestAlertTimestamp: '626569200000', }; -export const mockRiskScoreState: RiskScoreState = { - data: [userRiskScore], - inspect: { - dsl: [], - response: [], +export const mockObservedUser: ObservedEntityData = { + details: observedUserDetails, + isLoading: false, + firstSeen: { + isLoading: false, + date: '2023-02-23T20:03:17.489Z', + }, + lastSeen: { + isLoading: false, + date: '2023-02-23T20:03:17.489Z', + }, + anomalies: { + isLoading: false, + anomalies: { + anomalies: [anomaly], + interval: '', + }, + jobNameById: { [anomaly.jobId]: 'job_name' }, }, - isInspected: false, - refetch: () => {}, - totalCount: 0, - isModuleEnabled: true, - isAuthorized: true, - isDeprecated: false, - loading: false, }; diff --git a/x-pack/plugins/security_solution/public/flyout/index.tsx b/x-pack/plugins/security_solution/public/flyout/index.tsx index ef7e182324c63..c72417bd2004b 100644 --- a/x-pack/plugins/security_solution/public/flyout/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/index.tsx @@ -26,6 +26,11 @@ import type { UserPanelExpandableFlyoutProps } from './entity_details/user_right import { UserPanel, UserPanelKey } from './entity_details/user_right'; import type { UserDetailsPanelProps } from './entity_details/user_details_left'; import { UserDetailsPanel, UserDetailsPanelKey } from './entity_details/user_details_left'; +import type { HostPanelExpandableFlyoutProps } from './entity_details/host_right'; +import { HostPanel, HostPanelKey } from './entity_details/host_right'; +import type { HostDetailsExpandableFlyoutProps } from './entity_details/host_details_left'; +import { HostDetailsPanel, HostDetailsPanelKey } from './entity_details/host_details_left'; + /** * List of all panels that will be used within the document details expandable flyout. * This needs to be passed to the expandable flyout registeredPanels property. @@ -73,6 +78,16 @@ const expandableFlyoutDocumentsPanels: ExpandableFlyoutProps['registeredPanels'] ), }, + { + key: HostPanelKey, + component: (props) => , + }, + { + key: HostDetailsPanelKey, + component: (props) => ( + + ), + }, ]; export const SecuritySolutionFlyout = memo(() => ( diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/__mocks__/index.ts b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/__mocks__/index.ts index 65c6bd974b83a..43abce1104467 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/__mocks__/index.ts @@ -11,8 +11,7 @@ import type { } from '../../../../../../common/search_strategy/security_solution/users/managed_details'; import { ManagedUserDatasetKey } from '../../../../../../common/search_strategy/security_solution/users/managed_details'; import { RiskSeverity } from '../../../../../../common/search_strategy'; -import { mockAnomalies } from '../../../../../common/components/ml/mock'; -import type { ManagedUserData, ObservedUserData } from '../types'; +import type { ManagedUserData } from '../types'; const userRiskScore = { '@timestamp': '123456', @@ -44,43 +43,6 @@ export const mockRiskScoreState = { loading: false, }; -const anomaly = mockAnomalies.anomalies[0]; - -export const observedUserDetails = { - user: { - id: ['1234', '321'], - domain: ['test domain', 'another test domain'], - }, - host: { - ip: ['10.0.0.1', '127.0.0.1'], - os: { - name: ['testOs'], - family: ['testFamily'], - }, - }, -}; - -export const mockObservedUser: ObservedUserData = { - details: observedUserDetails, - isLoading: false, - firstSeen: { - isLoading: false, - date: '2023-02-23T20:03:17.489Z', - }, - lastSeen: { - isLoading: false, - date: '2023-02-23T20:03:17.489Z', - }, - anomalies: { - isLoading: false, - anomalies: { - anomalies: [anomaly], - interval: '', - }, - jobNameById: { [anomaly.jobId]: 'job_name' }, - }, -}; - export const mockOktaUserFields: ManagedUserFields = { '@timestamp': ['2023-11-16T13:42:23.074Z'], 'event.dataset': [ManagedUserDatasetKey.OKTA], diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/columns.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/columns.tsx index 8c4f31ea12141..da4e82976d515 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/columns.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/columns.tsx @@ -6,31 +6,16 @@ */ import { css } from '@emotion/react'; -import React, { useCallback } from 'react'; -import { head } from 'lodash/fp'; +import React from 'react'; import { euiLightVars } from '@kbn/ui-theme'; import type { EuiBasicTableColumn } from '@elastic/eui'; -import { useDispatch } from 'react-redux'; import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; import { DefaultFieldRenderer } from '../../field_renderers/field_renderers'; -import type { - ManagedUsersTableColumns, - ManagedUserTable, - ObservedUsersTableColumns, - ObservedUserTable, - UserAnomalies, -} from './types'; +import type { ManagedUsersTableColumns, ManagedUserTable } from './types'; import * as i18n from './translations'; import { defaultToEmptyTag } from '../../../../common/components/empty_value'; -import { FormattedRelativePreferenceDate } from '../../../../common/components/formatted_date'; -import { AnomalyScores } from '../../../../common/components/ml/score/anomaly_scores'; -import { useGlobalTime } from '../../../../common/containers/use_global_time'; -import { scoreIntervalToDateTime } from '../../../../common/components/ml/score/score_interval_to_datetime'; -import { InputsModelId } from '../../../../common/store/inputs/constants'; -import { setAbsoluteRangeDatePicker } from '../../../../common/store/inputs/actions'; -import { getSourcererScopeId } from '../../../../helpers'; -const fieldColumn: EuiBasicTableColumn = { +const fieldColumn: EuiBasicTableColumn = { name: i18n.FIELD_COLUMN_TITLE, field: 'label', render: (label: string, { field }) => ( @@ -68,71 +53,3 @@ export const getManagedUserTableColumns = ( }, }, ]; - -function isAnomalies( - field: string | undefined, - values: UserAnomalies | unknown -): values is UserAnomalies { - return field === 'anomalies'; -} - -export const getObservedUserTableColumns = ( - contextID: string, - scopeId: string, - isDraggable: boolean -): ObservedUsersTableColumns => [ - fieldColumn, - { - name: i18n.VALUES_COLUMN_TITLE, - field: 'values', - render: (values: ObservedUserTable['values'], { field }) => { - if (isAnomalies(field, values) && values) { - return ; - } - - if (field === '@timestamp') { - return ; - } - - return ( - - ); - }, - }, -]; - -const AnomaliesField = ({ anomalies }: { anomalies: UserAnomalies }) => { - const { to, from } = useGlobalTime(); - const dispatch = useDispatch(); - - const narrowDateRange = useCallback( - (score, interval) => { - const fromTo = scoreIntervalToDateTime(score, interval); - dispatch( - setAbsoluteRangeDatePicker({ - id: InputsModelId.global, - from: fromTo.from, - to: fromTo.to, - }) - ); - }, - [dispatch] - ); - - return ( - - ); -}; diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/hooks/use_observed_user_items.ts b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/hooks/use_observed_user_items.ts deleted file mode 100644 index d6390b210d586..0000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/hooks/use_observed_user_items.ts +++ /dev/null @@ -1,48 +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 { useMemo } from 'react'; -import * as i18n from '../translations'; -import type { ObservedUserData, ObservedUserTable } from '../types'; - -export const useObservedUserItems = (userData: ObservedUserData): ObservedUserTable[] => - useMemo( - () => - !userData.details - ? [] - : [ - { label: i18n.USER_ID, values: userData.details.user?.id, field: 'user.id' }, - { label: 'Domain', values: userData.details.user?.domain, field: 'user.domain' }, - { - label: i18n.MAX_ANOMALY_SCORE_BY_JOB, - field: 'anomalies', - values: userData.anomalies, - }, - { - label: i18n.FIRST_SEEN, - values: userData.firstSeen.date ? [userData.firstSeen.date] : undefined, - field: '@timestamp', - }, - { - label: i18n.LAST_SEEN, - values: userData.lastSeen.date ? [userData.lastSeen.date] : undefined, - field: '@timestamp', - }, - { - label: i18n.OPERATING_SYSTEM_TITLE, - values: userData.details.host?.os?.name, - field: 'host.os.name', - }, - { - label: i18n.FAMILY, - values: userData.details.host?.os?.family, - field: 'host.os.family', - }, - { label: i18n.IP_ADDRESSES, values: userData.details.host?.ip, field: 'host.ip' }, - ], - [userData.details, userData.anomalies, userData.firstSeen, userData.lastSeen] - ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/managed_user.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/managed_user.tsx index 590f120b19687..635cf6a2868fd 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/managed_user.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/managed_user.tsx @@ -18,7 +18,7 @@ import { import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/css'; -import type { UserDetailsLeftPanelTab } from '../../../../flyout/entity_details/user_details_left/tabs'; +import type { EntityDetailsLeftPanelTab } from '../../../../flyout/entity_details/shared/components/left_panel/left_panel_header'; import { UserAssetTableType } from '../../../../explore/users/store/model'; import type { ManagedUserFields } from '../../../../../common/search_strategy/security_solution/users/managed_details'; import { ManagedUserDatasetKey } from '../../../../../common/search_strategy/security_solution/users/managed_details'; @@ -47,7 +47,7 @@ export const ManagedUser = ({ managedUser: ManagedUserData; contextID: string; isDraggable: boolean; - openDetailsPanel: (tab: UserDetailsLeftPanelTab) => void; + openDetailsPanel: (tab: EntityDetailsLeftPanelTab) => void; }) => { const entraManagedUser = managedUser.data?.[ManagedUserDatasetKey.ENTRA]; const oktaManagedUser = managedUser.data?.[ManagedUserDatasetKey.OKTA]; diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/managed_user_accordion.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/managed_user_accordion.tsx index a03775f61cf26..ad8b089adc168 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/managed_user_accordion.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/managed_user_accordion.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { css } from '@emotion/react'; import { FormattedMessage } from '@kbn/i18n-react'; import { get } from 'lodash/fp'; -import { UserDetailsLeftPanelTab } from '../../../../flyout/entity_details/user_details_left/tabs'; +import { EntityDetailsLeftPanelTab } from '../../../../flyout/entity_details/shared/components/left_panel/left_panel_header'; import { ExpandablePanel } from '../../../../flyout/shared/components/expandable_panel'; import type { ManagedUserFields } from '../../../../../common/search_strategy/security_solution/users/managed_details'; @@ -23,7 +23,7 @@ interface ManagedUserAccordionProps { title: string; managedUser: ManagedUserFields; tableType: UserAssetTableType; - openDetailsPanel: (tab: UserDetailsLeftPanelTab) => void; + openDetailsPanel: (tab: EntityDetailsLeftPanelTab) => void; } export const ManagedUserAccordion: React.FC = ({ @@ -66,8 +66,8 @@ export const ManagedUserAccordion: React.FC = ({ callback: () => openDetailsPanel( tableType === UserAssetTableType.assetOkta - ? UserDetailsLeftPanelTab.OKTA - : UserDetailsLeftPanelTab.ENTRA + ? EntityDetailsLeftPanelTab.OKTA + : EntityDetailsLeftPanelTab.ENTRA ), tooltip: ( { - const mockProps = { - observedUser: mockObservedUser, - contextID: '', - scopeId: '', - isDraggable: false, - }; - - it('renders', () => { - const { getByTestId } = render( - - - - ); - - expect(getByTestId('observedUser-data')).toBeInTheDocument(); - }); - - it('renders the formatted date', () => { - const { getByTestId } = render( - - - - ); - - expect(getByTestId('observedUser-data')).toHaveTextContent('Updated Feb 23, 2023'); - }); - - it('renders anomaly score', () => { - const { getByTestId } = render( - - - - ); - - expect(getByTestId('anomaly-score')).toHaveTextContent('17'); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/risk_score_field.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/risk_score_field.test.tsx deleted file mode 100644 index 48d927c97030c..0000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/risk_score_field.test.tsx +++ /dev/null @@ -1,46 +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 { render } from '@testing-library/react'; -import React from 'react'; -import { TestProviders } from '../../../../common/mock'; -import { RiskScoreField } from './risk_score_field'; -import { mockRiskScoreState } from './__mocks__'; -import { getEmptyValue } from '../../../../common/components/empty_value'; - -describe('RiskScoreField', () => { - it('renders', () => { - const { getByTestId } = render( - - - - ); - - expect(getByTestId('user-details-risk-score')).toBeInTheDocument(); - expect(getByTestId('user-details-risk-score')).toHaveTextContent('70'); - }); - - it('does not render content when the license is invalid', () => { - const { queryByTestId } = render( - - - - ); - - expect(queryByTestId('user-details-risk-score')).not.toBeInTheDocument(); - }); - - it('renders empty tag when risk score is undefined', () => { - const { getByTestId } = render( - - - - ); - - expect(getByTestId('user-details-risk-score')).toHaveTextContent(getEmptyValue()); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/risk_score_field.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/risk_score_field.tsx deleted file mode 100644 index fab77b92582f6..0000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/risk_score_field.tsx +++ /dev/null @@ -1,79 +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 { EuiFlexItem, EuiFlexGroup, useEuiFontSize, useEuiTheme } from '@elastic/eui'; - -import React from 'react'; -import { css } from '@emotion/react'; - -import styled from 'styled-components'; -import * as i18n from './translations'; - -import { RiskScoreEntity } from '../../../../../common/search_strategy'; -import { getEmptyTagValue } from '../../../../common/components/empty_value'; -import { RiskScoreLevel } from '../../../../entity_analytics/components/severity/common'; -import type { RiskScoreState } from '../../../../entity_analytics/api/hooks/use_risk_score'; -import { RiskScoreDocTooltip } from '../../../../overview/components/common'; - -export const TooltipContainer = styled.div` - padding: ${({ theme }) => theme.eui.euiSizeS}; -`; - -export const RiskScoreField = ({ - riskScoreState, -}: { - riskScoreState: RiskScoreState; -}) => { - const { euiTheme } = useEuiTheme(); - const { fontSize: xsFontSize } = useEuiFontSize('xs'); - const { data: userRisk, isAuthorized: isRiskScoreAuthorized } = riskScoreState; - const userRiskData = userRisk && userRisk.length > 0 ? userRisk[0] : undefined; - - if (!isRiskScoreAuthorized) { - return null; - } - - return ( - - - - {i18n.RISK_SCORE} - {': '} - - - {userRiskData ? ( - - - {Math.round(userRiskData.user.risk.calculated_score_norm)} - - - - - - - - - ) : ( - getEmptyTagValue() - )} - - ); -}; diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/translations.ts b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/translations.ts index ce5e34ce3249b..ebeb5d26cf362 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/translations.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/translations.ts @@ -81,49 +81,6 @@ export const FIELD_COLUMN_TITLE = i18n.translate( } ); -export const USER_ID = i18n.translate('xpack.securitySolution.timeline.userDetails.userIdLabel', { - defaultMessage: 'User ID', -}); - -export const MAX_ANOMALY_SCORE_BY_JOB = i18n.translate( - 'xpack.securitySolution.timeline.userDetails.maxAnomalyScoreByJobLabel', - { - defaultMessage: 'Max anomaly score by job', - } -); - -export const FIRST_SEEN = i18n.translate( - 'xpack.securitySolution.timeline.userDetails.firstSeenLabel', - { - defaultMessage: 'First seen', - } -); - -export const LAST_SEEN = i18n.translate( - 'xpack.securitySolution.timeline.userDetails.lastSeenLabel', - { - defaultMessage: 'Last seen', - } -); - -export const OPERATING_SYSTEM_TITLE = i18n.translate( - 'xpack.securitySolution.timeline.userDetails.hostOsNameLabel', - { - defaultMessage: 'Operating system', - } -); - -export const FAMILY = i18n.translate('xpack.securitySolution.timeline.userDetails.familyLabel', { - defaultMessage: 'Family', -}); - -export const IP_ADDRESSES = i18n.translate( - 'xpack.securitySolution.timeline.userDetails.ipAddressesLabel', - { - defaultMessage: 'IP addresses', - } -); - export const NO_ACTIVE_INTEGRATION_TITLE = i18n.translate( 'xpack.securitySolution.timeline.userDetails.noActiveIntegrationTitle', { @@ -168,13 +125,6 @@ export const CLOSE_BUTTON = i18n.translate( } ); -export const OBSERVED_USER_INSPECT_TITLE = i18n.translate( - 'xpack.securitySolution.timeline.userDetails.observedUserInspectTitle', - { - defaultMessage: 'Observed user', - } -); - export const MANAGED_USER_INSPECT_TITLE = i18n.translate( 'xpack.securitySolution.timeline.userDetails.managedUserInspectTitle', { diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/types.ts b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/types.ts index edefb6ac75100..721ba17370709 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/types.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/types.ts @@ -7,44 +7,17 @@ import type { EuiBasicTableColumn } from '@elastic/eui'; import type { SearchTypes } from '../../../../../common/detection_engine/types'; -import type { UserItem } from '../../../../../common/search_strategy'; import type { ManagedUserHits } from '../../../../../common/search_strategy/security_solution/users/managed_details'; -import type { AnomalyTableProviderChildrenProps } from '../../../../common/components/ml/anomaly/anomaly_table_provider'; - -export interface ObservedUserTable { - values: string[] | null | undefined | UserAnomalies; - field: string; -} export interface ManagedUserTable { value: SearchTypes[]; field?: string; } -export type ObservedUsersTableColumns = Array>; export type ManagedUsersTableColumns = Array>; -export interface ObservedUserData { - isLoading: boolean; - details: UserItem; - firstSeen: FirstLastSeenData; - lastSeen: FirstLastSeenData; - anomalies: UserAnomalies; -} - export interface ManagedUserData { isLoading: boolean; data: ManagedUserHits | undefined; isIntegrationEnabled: boolean; } - -export interface FirstLastSeenData { - date: string | null | undefined; - isLoading: boolean; -} - -export interface UserAnomalies { - isLoading: AnomalyTableProviderChildrenProps['isLoadingAnomaliesData']; - anomalies: AnomalyTableProviderChildrenProps['anomaliesData']; - jobNameById: AnomalyTableProviderChildrenProps['jobNameById']; -} diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx index 1535b05a97a4f..437f8be9de10c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx @@ -17,6 +17,23 @@ import { StatefulEventContext } from '../../../../../common/components/events_vi import { createTelemetryServiceMock } from '../../../../../common/lib/telemetry/telemetry_service.mock'; const mockedTelemetry = createTelemetryServiceMock(); +const mockUseIsExperimentalFeatureEnabled = jest.fn(); +const mockOpenRightPanel = jest.fn(); + +jest.mock('../../../../../common/hooks/use_experimental_features', () => ({ + useIsExperimentalFeatureEnabled: () => mockUseIsExperimentalFeatureEnabled, +})); + +jest.mock('@kbn/expandable-flyout/src/context', () => { + const original = jest.requireActual('@kbn/expandable-flyout/src/context'); + + return { + ...original, + useExpandableFlyoutContext: () => ({ + openRightPanel: mockOpenRightPanel, + }), + }; +}); jest.mock('react-redux', () => { const origin = jest.requireActual('react-redux'); @@ -197,4 +214,27 @@ describe('HostName', () => { expect(toggleExpandedDetail).not.toHaveBeenCalled(); }); }); + + test('it should open expandable flyout if timeline is not in context and experimental flag is enabled', async () => { + mockUseIsExperimentalFeatureEnabled.mockReturnValue(true); + const context = { + enableHostDetailsFlyout: true, + enableIpDetailsFlyout: true, + timelineID: 'fake-timeline', + tabType: TimelineTabs.query, + }; + const wrapper = mount( + + + + + + ); + + wrapper.find('[data-test-subj="host-details-button"]').last().simulate('click'); + await waitFor(() => { + expect(mockOpenRightPanel).toHaveBeenCalled(); + expect(toggleExpandedDetail).not.toHaveBeenCalled(); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.tsx index 37503f7b905ec..c6b8d4f2d4cd3 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.tsx @@ -9,9 +9,13 @@ import React, { useCallback, useContext, useMemo } from 'react'; import type { EuiButtonEmpty, EuiButtonIcon } from '@elastic/eui'; import { useDispatch } from 'react-redux'; import { isString } from 'lodash/fp'; +import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { TableId } from '@kbn/securitysolution-data-table'; +import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; +import { HostPanelKey } from '../../../../../flyout/entity_details/host_right'; import type { ExpandedDetailType } from '../../../../../../common/types'; import { StatefulEventContext } from '../../../../../common/components/events_viewer/stateful_event_context'; -import { getScopedActions } from '../../../../../helpers'; +import { getScopedActions, isTimelineScope } from '../../../../../helpers'; import { HostDetailsLink } from '../../../../../common/components/links'; import { TimelineId, TimelineTabs } from '../../../../../../common/types/timeline'; import { DefaultDraggable } from '../../../../../common/components/draggables'; @@ -46,6 +50,9 @@ const HostNameComponent: React.FC = ({ title, value, }) => { + const isNewHostDetailsFlyoutEnabled = useIsExperimentalFeatureEnabled('newHostDetailsFlyout'); + const { openRightPanel } = useExpandableFlyoutContext(); + const dispatch = useDispatch(); const eventContext = useContext(StatefulEventContext); const hostName = `${value}`; @@ -58,31 +65,55 @@ const HostNameComponent: React.FC = ({ if (onClick) { onClick(); } + if (eventContext && isInTimelineContext) { const { timelineID, tabType } = eventContext; - const updatedExpandedDetail: ExpandedDetailType = { - panelView: 'hostDetail', - params: { - hostName, - }, - }; - const scopedActions = getScopedActions(timelineID); - if (scopedActions) { - dispatch( - scopedActions.toggleDetailPanel({ - ...updatedExpandedDetail, - id: timelineID, - tabType: tabType as TimelineTabs, - }) - ); - } - if (timelineID === TimelineId.active && tabType === TimelineTabs.query) { - activeTimeline.toggleExpandedDetail({ ...updatedExpandedDetail }); + if (isNewHostDetailsFlyoutEnabled && !isTimelineScope(timelineID)) { + openRightPanel({ + id: HostPanelKey, + params: { + hostName, + contextID: contextId, + scopeId: TableId.alertsOnAlertsPage, + isDraggable, + }, + }); + } else { + const updatedExpandedDetail: ExpandedDetailType = { + panelView: 'hostDetail', + params: { + hostName, + }, + }; + const scopedActions = getScopedActions(timelineID); + if (scopedActions) { + dispatch( + scopedActions.toggleDetailPanel({ + ...updatedExpandedDetail, + id: timelineID, + tabType: tabType as TimelineTabs, + }) + ); + } + + if (timelineID === TimelineId.active && tabType === TimelineTabs.query) { + activeTimeline.toggleExpandedDetail({ ...updatedExpandedDetail }); + } } } }, - [onClick, eventContext, isInTimelineContext, hostName, dispatch] + [ + onClick, + eventContext, + isInTimelineContext, + isNewHostDetailsFlyoutEnabled, + openRightPanel, + hostName, + contextId, + isDraggable, + dispatch, + ] ); // The below is explicitly defined this way as the onClick takes precedence when it and the href are both defined diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 9942bbf4508e3..cbbd515a86e1b 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -32020,7 +32020,6 @@ "xpack.securitySolution.timeline.properties.timelineToggleButtonAriaLabel": "{isOpen, select, false {Ouvrir} true {Fermer} other {Bascule}} la chronologie {title}", "xpack.securitySolution.timeline.saveTimeline.modal.warning.title": "Vous avez une {timeline} non enregistrée. Voulez-vous l'enregistrer ?", "xpack.securitySolution.timeline.searchBoxPlaceholder": "par ex. nom ou description de {timeline}", - "xpack.securitySolution.timeline.userDetails.observedUserUpdatedTime": "Mis à jour {time}", "xpack.securitySolution.timeline.userDetails.updatedTime": "Mis à jour {time}", "xpack.securitySolution.timeline.youAreInAnEventRendererScreenReaderOnly": "Vous êtes dans un outil de rendu d'événement pour la ligne : {row}. Appuyez sur la touche fléchée vers le haut pour quitter et revenir à la ligne en cours, ou sur la touche fléchée vers le bas pour quitter et passer à la ligne suivante.", "xpack.securitySolution.timeline.youAreInATableCellScreenReaderOnly": "Vous êtes dans une cellule de tableau. Ligne : {row}, colonne : {column}", @@ -36361,25 +36360,17 @@ "xpack.securitySolution.timeline.userDetails.addExternalIntegrationButton": "Ajouter des intégrations externes", "xpack.securitySolution.timeline.userDetails.closeButton": "fermer", "xpack.securitySolution.timeline.userDetails.failManagedUserDescription": "Impossible de lancer la recherche sur des données gérées par l'utilisateur", - "xpack.securitySolution.timeline.userDetails.familyLabel": "Famille", "xpack.securitySolution.timeline.userDetails.fieldColumnTitle": "Champ", - "xpack.securitySolution.timeline.userDetails.firstSeenLabel": "Vu en premier", - "xpack.securitySolution.timeline.userDetails.hostOsNameLabel": "Système d'exploitation", - "xpack.securitySolution.timeline.userDetails.ipAddressesLabel": "Adresses IP", - "xpack.securitySolution.timeline.userDetails.lastSeenLabel": "Vu en dernier", "xpack.securitySolution.timeline.userDetails.managedBadge": "GÉRÉ", "xpack.securitySolution.timeline.userDetails.managedDataTitle": "Données gérées", "xpack.securitySolution.timeline.userDetails.managedUserInspectTitle": "Géré par l'utilisateur", - "xpack.securitySolution.timeline.userDetails.maxAnomalyScoreByJobLabel": "Score maximal d'anomalie par tâche", "xpack.securitySolution.timeline.userDetails.noActiveIntegrationText": "Les intégrations externes peuvent fournir des métadonnées supplémentaires et vous aider à gérer les utilisateurs.", "xpack.securitySolution.timeline.userDetails.noActiveIntegrationTitle": "Vous n'avez aucune intégration active.", "xpack.securitySolution.timeline.userDetails.noAzureDataText": "Si vous vous attendiez à voir des métadonnées pour cet utilisateur, assurez-vous d'avoir correctement configuré vos intégrations.", "xpack.securitySolution.timeline.userDetails.noAzureDataTitle": "Métadonnées introuvables pour cet utilisateur", "xpack.securitySolution.timeline.userDetails.observedBadge": "OBSERVÉ", "xpack.securitySolution.timeline.userDetails.observedDataTitle": "Données observées", - "xpack.securitySolution.timeline.userDetails.observedUserInspectTitle": "Utilisateur observé", "xpack.securitySolution.timeline.userDetails.riskScoreLabel": "Score de risque", - "xpack.securitySolution.timeline.userDetails.userIdLabel": "ID utilisateur", "xpack.securitySolution.timeline.userDetails.userLabel": "Utilisateur", "xpack.securitySolution.timeline.userDetails.valuesColumnTitle": "Valeurs", "xpack.securitySolution.timelineEvents.errorSearchDescription": "Une erreur s'est produite lors de la recherche d'événements de la chronologie", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index d569cab16ee93..f0575cc0496fb 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -32019,7 +32019,6 @@ "xpack.securitySolution.timeline.properties.timelineToggleButtonAriaLabel": "タイムライン\"{title}\"を{isOpen, select, false {開く} true {閉じる} other {切り替え}}", "xpack.securitySolution.timeline.saveTimeline.modal.warning.title": "保存されていない{timeline}があります。保存しますか?", "xpack.securitySolution.timeline.searchBoxPlaceholder": "例:{timeline}名または説明", - "xpack.securitySolution.timeline.userDetails.observedUserUpdatedTime": "{time}を更新しました", "xpack.securitySolution.timeline.userDetails.updatedTime": "{time}を更新しました", "xpack.securitySolution.timeline.youAreInAnEventRendererScreenReaderOnly": "行{row}のイベントレンダラーを表示しています。上矢印キーを押すと、終了して現在の行に戻ります。下矢印キーを押すと、終了して次の行に進みます。", "xpack.securitySolution.timeline.youAreInATableCellScreenReaderOnly": "表セルの行{row}、列{column}にいます", @@ -36360,25 +36359,17 @@ "xpack.securitySolution.timeline.userDetails.addExternalIntegrationButton": "外部統合を追加", "xpack.securitySolution.timeline.userDetails.closeButton": "閉じる", "xpack.securitySolution.timeline.userDetails.failManagedUserDescription": "ユーザーが管理するデータで検索を実行できませんでした", - "xpack.securitySolution.timeline.userDetails.familyLabel": "ファミリー", "xpack.securitySolution.timeline.userDetails.fieldColumnTitle": "フィールド", - "xpack.securitySolution.timeline.userDetails.firstSeenLabel": "初回の認識", - "xpack.securitySolution.timeline.userDetails.hostOsNameLabel": "オペレーティングシステム", - "xpack.securitySolution.timeline.userDetails.ipAddressesLabel": "IP アドレス", - "xpack.securitySolution.timeline.userDetails.lastSeenLabel": "前回の認識", "xpack.securitySolution.timeline.userDetails.managedBadge": "管理対象", "xpack.securitySolution.timeline.userDetails.managedDataTitle": "管理対象のデータ", "xpack.securitySolution.timeline.userDetails.managedUserInspectTitle": "管理対象のユーザー", - "xpack.securitySolution.timeline.userDetails.maxAnomalyScoreByJobLabel": "ジョブ別の最高異常スコア", "xpack.securitySolution.timeline.userDetails.noActiveIntegrationText": "外部統合は追加のメタデータを提供し、ユーザーの管理を支援できます。", "xpack.securitySolution.timeline.userDetails.noActiveIntegrationTitle": "アクティブな統合がありません", "xpack.securitySolution.timeline.userDetails.noAzureDataText": "このユーザーのメタデータが表示されることが想定される場合は、統合を正しく構成したことを確認してください。", "xpack.securitySolution.timeline.userDetails.noAzureDataTitle": "このユーザーのメタデータが見つかりません", "xpack.securitySolution.timeline.userDetails.observedBadge": "観測済み", "xpack.securitySolution.timeline.userDetails.observedDataTitle": "観測されたデータ", - "xpack.securitySolution.timeline.userDetails.observedUserInspectTitle": "観測されたユーザー", "xpack.securitySolution.timeline.userDetails.riskScoreLabel": "リスクスコア", - "xpack.securitySolution.timeline.userDetails.userIdLabel": "ユーザーID", "xpack.securitySolution.timeline.userDetails.userLabel": "ユーザー", "xpack.securitySolution.timeline.userDetails.valuesColumnTitle": "値", "xpack.securitySolution.timelineEvents.errorSearchDescription": "タイムラインイベント検索でエラーが発生しました", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 06fe50fdae469..2a5c081a8d014 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -32001,7 +32001,6 @@ "xpack.securitySolution.timeline.properties.timelineToggleButtonAriaLabel": "{isOpen, select, false {打开} true {关闭} other {切换}}时间线 {title}", "xpack.securitySolution.timeline.saveTimeline.modal.warning.title": "您的 {timeline} 未保存。是否保存?", "xpack.securitySolution.timeline.searchBoxPlaceholder": "例如 {timeline} 名称或描述", - "xpack.securitySolution.timeline.userDetails.observedUserUpdatedTime": "已更新 {time}", "xpack.securitySolution.timeline.userDetails.updatedTime": "已更新 {time}", "xpack.securitySolution.timeline.youAreInAnEventRendererScreenReaderOnly": "您正处于第 {row} 行的事件呈现器中。按向上箭头键退出并返回当前行,或按向下箭头键退出并前进到下一行。", "xpack.securitySolution.timeline.youAreInATableCellScreenReaderOnly": "您处在表单元格中。行:{row},列:{column}", @@ -36342,25 +36341,17 @@ "xpack.securitySolution.timeline.userDetails.addExternalIntegrationButton": "添加外部集成", "xpack.securitySolution.timeline.userDetails.closeButton": "关闭", "xpack.securitySolution.timeline.userDetails.failManagedUserDescription": "无法对用户托管数据执行搜索", - "xpack.securitySolution.timeline.userDetails.familyLabel": "系列", "xpack.securitySolution.timeline.userDetails.fieldColumnTitle": "字段", - "xpack.securitySolution.timeline.userDetails.firstSeenLabel": "首次看到时间", - "xpack.securitySolution.timeline.userDetails.hostOsNameLabel": "操作系统", - "xpack.securitySolution.timeline.userDetails.ipAddressesLabel": "IP 地址", - "xpack.securitySolution.timeline.userDetails.lastSeenLabel": "最后看到时间", "xpack.securitySolution.timeline.userDetails.managedBadge": "托管", "xpack.securitySolution.timeline.userDetails.managedDataTitle": "托管数据", "xpack.securitySolution.timeline.userDetails.managedUserInspectTitle": "托管用户", - "xpack.securitySolution.timeline.userDetails.maxAnomalyScoreByJobLabel": "最大异常分数(按作业)", "xpack.securitySolution.timeline.userDetails.noActiveIntegrationText": "外部集成可提供其他元数据并帮助您管理用户。", "xpack.securitySolution.timeline.userDetails.noActiveIntegrationTitle": "您没有任何活动集成", "xpack.securitySolution.timeline.userDetails.noAzureDataText": "如果计划查看此用户的元数据,请确保已正确配置集成。", "xpack.securitySolution.timeline.userDetails.noAzureDataTitle": "找不到此用户的元数据", "xpack.securitySolution.timeline.userDetails.observedBadge": "已观察", "xpack.securitySolution.timeline.userDetails.observedDataTitle": "观察数据", - "xpack.securitySolution.timeline.userDetails.observedUserInspectTitle": "已观察用户", "xpack.securitySolution.timeline.userDetails.riskScoreLabel": "风险分数", - "xpack.securitySolution.timeline.userDetails.userIdLabel": "用户 ID", "xpack.securitySolution.timeline.userDetails.userLabel": "用户", "xpack.securitySolution.timeline.userDetails.valuesColumnTitle": "值", "xpack.securitySolution.timelineEvents.errorSearchDescription": "搜索时间线事件时发生错误", From e4cac3725f50ab16d1c8df543a4fd0e3fde1e843 Mon Sep 17 00:00:00 2001 From: Alexi Doak <109488926+doakalexi@users.noreply.github.com> Date: Thu, 4 Jan 2024 07:03:52 -0800 Subject: [PATCH 014/100] [ResponseOps][Alerting] Update the size of the input labels for the ES query and index threshold rule (#174137) Resolves https://github.com/elastic/kibana/issues/173857 ## Summary Updates the size of the input labels for the ES query and index threshold rules. It is helpful to hide whitespace when reviewing the code changes. **KQL** Screen Shot 2024-01-03 at 10 03 36 AM **Query DSL** Screen Shot 2024-01-03 at 10 04 06 AM **ES|QL** Screen Shot 2024-01-03 at 10 04 35 AM **Index Threshold** Screen Shot 2024-01-03 at 10 02 29 AM --- .../components/source_fields_select.tsx | 69 +++++++------- .../expression/es_query_expression.tsx | 95 +++++++++---------- .../expression/esql_query_expression.tsx | 46 ++++----- .../search_source_expression_form.tsx | 27 +++--- .../rule_common_expressions.tsx | 86 ++++++++--------- .../rule_types/threshold/expression.tsx | 95 ++++++++++--------- 6 files changed, 196 insertions(+), 222 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/rule_types/components/source_fields_select.tsx b/x-pack/plugins/stack_alerts/public/rule_types/components/source_fields_select.tsx index 3cd34a3cd0015..79b2e6ca4ed16 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/components/source_fields_select.tsx +++ b/x-pack/plugins/stack_alerts/public/rule_types/components/source_fields_select.tsx @@ -7,7 +7,7 @@ import React, { useEffect, useState } from 'react'; import { uniqBy } from 'lodash'; -import { EuiComboBox, EuiFormRow, EuiSpacer, EuiTitle } from '@elastic/eui'; +import { EuiComboBox, EuiFormRow } from '@elastic/eui'; import { FieldOption } from '@kbn/triggers-actions-ui-plugin/public/common'; import { IErrorObject } from '@kbn/triggers-actions-ui-plugin/public'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -77,44 +77,39 @@ export const SourceFields: React.FC = ({ fullWidth isInvalid={errors.length > 0 && sourceFields !== undefined} error={errors} + label={ + + } > - <> - -
- -
-
- - 0 && sourceFields !== undefined} + selectedOptions={(sourceFields || []).map((f) => ({ + label: f.label, + value: f.searchPath, + 'data-test-subj': `option-${f.label}`, + }))} + onChange={(options) => { + const fields: SourceField[] = []; + options.forEach((f) => { + if (f.value) { + fields.push({ label: f.label, searchPath: f.value }); } - )} - data-test-subj="sourceFields" - isInvalid={errors.length > 0 && sourceFields !== undefined} - selectedOptions={(sourceFields || []).map((f) => ({ - label: f.label, - value: f.searchPath, - 'data-test-subj': `option-${f.label}`, - }))} - onChange={(options) => { - const fields: SourceField[] = []; - options.forEach((f) => { - if (f.value) { - fields.push({ label: f.label, searchPath: f.value }); - } - }); - onChangeSourceFields(fields); - }} - options={sourceFieldsOptions} - /> - + }); + onChangeSourceFields(fields); + }} + options={sourceFieldsOptions} + /> ) : null; }; diff --git a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/es_query_expression.tsx b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/es_query_expression.tsx index 1cf901ecae8f9..66a1ca82feff5 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/es_query_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/es_query_expression.tsx @@ -11,7 +11,7 @@ import { lastValueFrom } from 'rxjs'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiFormRow, EuiLink, EuiSpacer, EuiTitle } from '@elastic/eui'; +import { EuiFormRow, EuiLink, EuiSpacer } from '@elastic/eui'; import { XJson } from '@kbn/es-ui-shared-plugin/public'; import { CodeEditor } from '@kbn/kibana-react-plugin/public'; @@ -195,60 +195,49 @@ export const EsQueryExpression: React.FC< return ( - -
+ -
-
- - - - { - setParam('index', indices); - - // reset expression fields if indices are deleted - if (indices.length === 0) { - setRuleProperty('params', { - timeField: ruleParams.timeField, - index: indices, - esQuery: DEFAULT_VALUES.QUERY, - size: DEFAULT_VALUES.SIZE, - thresholdComparator: DEFAULT_VALUES.THRESHOLD_COMPARATOR, - timeWindowSize: DEFAULT_VALUES.TIME_WINDOW_SIZE, - timeWindowUnit: DEFAULT_VALUES.TIME_WINDOW_UNIT, - threshold: DEFAULT_VALUES.THRESHOLD, - aggType: DEFAULT_VALUES.AGGREGATION_TYPE, - groupBy: DEFAULT_VALUES.GROUP_BY, - termSize: DEFAULT_VALUES.TERM_SIZE, - searchType: SearchType.esQuery, - excludeHitsFromPreviousRun: DEFAULT_VALUES.EXCLUDE_PREVIOUS_HITS, - sourceFields: undefined, - }); - } else { - await refreshEsFields(indices); - } - }} - onTimeFieldChange={(updatedTimeField: string) => setParam('timeField', updatedTimeField)} - /> - + } + > + { + setParam('index', indices); - -
- -
-
+ // reset expression fields if indices are deleted + if (indices.length === 0) { + setRuleProperty('params', { + timeField: ruleParams.timeField, + index: indices, + esQuery: DEFAULT_VALUES.QUERY, + size: DEFAULT_VALUES.SIZE, + thresholdComparator: DEFAULT_VALUES.THRESHOLD_COMPARATOR, + timeWindowSize: DEFAULT_VALUES.TIME_WINDOW_SIZE, + timeWindowUnit: DEFAULT_VALUES.TIME_WINDOW_UNIT, + threshold: DEFAULT_VALUES.THRESHOLD, + aggType: DEFAULT_VALUES.AGGREGATION_TYPE, + groupBy: DEFAULT_VALUES.GROUP_BY, + termSize: DEFAULT_VALUES.TERM_SIZE, + searchType: SearchType.esQuery, + excludeHitsFromPreviousRun: DEFAULT_VALUES.EXCLUDE_PREVIOUS_HITS, + sourceFields: undefined, + }); + } else { + await refreshEsFields(indices); + } + }} + onTimeFieldChange={(updatedTimeField: string) => setParam('timeField', updatedTimeField)} + /> + } + label={ + + } > - -
+ -
-
- - + } + > { @@ -215,20 +215,17 @@ export const EsqlQueryExpression: React.FC< errors={errors.sourceFields} /> - -
- -
-
- 0 && timeField !== undefined} error={errors.timeField} + label={ + + } > - -
- -
-
- - + 0} error={errors.timeWindowSize} + label={ + + } > - -
+ -
-
- - + } + > + +
{Boolean(dataView?.id) && ( <> diff --git a/x-pack/plugins/stack_alerts/public/rule_types/es_query/rule_common_expressions/rule_common_expressions.tsx b/x-pack/plugins/stack_alerts/public/rule_types/es_query/rule_common_expressions/rule_common_expressions.tsx index 313d3f586c73e..c356104ed831f 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/es_query/rule_common_expressions/rule_common_expressions.tsx +++ b/x-pack/plugins/stack_alerts/public/rule_types/es_query/rule_common_expressions/rule_common_expressions.tsx @@ -7,15 +7,7 @@ import React, { useEffect, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { - EuiCheckbox, - EuiFlexGroup, - EuiFlexItem, - EuiFormRow, - EuiIconTip, - EuiSpacer, - EuiTitle, -} from '@elastic/eui'; +import { EuiCheckbox, EuiFormRow, EuiIconTip, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { builtInAggregationTypes, @@ -98,22 +90,23 @@ export const RuleCommonExpressions: React.FC = ({ }, [groupBy]); return ( <> - -

+ {' '} - -

-
- - + />, + , + ]} + > + +
{aggType && builtInAggregationTypes[aggType].fieldRequired ? ( = ({ onChangeWindowUnit={onChangeWindowUnit} /> - - - -
- -
-
-
- + , = ({ defaultMessage: 'Specify the number of documents to pass to the configured actions when the threshold condition is met.', })} - /> - -
- - + />, + ]} + > + +
) : null} - -
+ -
-
- - { - setRuleParams('index', indices); + } + > + { + setRuleParams('index', indices); - // reset expression fields if indices are deleted - if (indices.length === 0) { - setRuleProperty('params', { - ...ruleParams, - index: indices, - aggType: DEFAULT_VALUES.AGGREGATION_TYPE, - termSize: DEFAULT_VALUES.TERM_SIZE, - thresholdComparator: DEFAULT_VALUES.THRESHOLD_COMPARATOR, - timeWindowSize: DEFAULT_VALUES.TIME_WINDOW_SIZE, - timeWindowUnit: DEFAULT_VALUES.TIME_WINDOW_UNIT, - groupBy: DEFAULT_VALUES.GROUP_BY, - threshold: DEFAULT_VALUES.THRESHOLD, - timeField: '', - }); - } else { - await refreshEsFields(indices); + // reset expression fields if indices are deleted + if (indices.length === 0) { + setRuleProperty('params', { + ...ruleParams, + index: indices, + aggType: DEFAULT_VALUES.AGGREGATION_TYPE, + termSize: DEFAULT_VALUES.TERM_SIZE, + thresholdComparator: DEFAULT_VALUES.THRESHOLD_COMPARATOR, + timeWindowSize: DEFAULT_VALUES.TIME_WINDOW_SIZE, + timeWindowUnit: DEFAULT_VALUES.TIME_WINDOW_UNIT, + groupBy: DEFAULT_VALUES.GROUP_BY, + threshold: DEFAULT_VALUES.THRESHOLD, + timeField: '', + }); + } else { + await refreshEsFields(indices); + } + }} + onTimeFieldChange={(updatedTimeField: string) => + setRuleParams('timeField', updatedTimeField) } - }} - onTimeFieldChange={(updatedTimeField: string) => - setRuleParams('timeField', updatedTimeField) - } - /> + /> + - -
+ -
-
- - - setRuleParams('aggType', selectedAggType) } - /> + > + + setRuleParams('aggType', selectedAggType) + } + /> + {aggType && builtInAggregationTypes[aggType].fieldRequired ? ( Date: Thu, 4 Jan 2024 08:17:41 -0700 Subject: [PATCH 015/100] [Dashboard] Update embed mode test screenshot (#174193) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes https://github.com/elastic/kibana/issues/163207 ## Summary This PR updates the embed mode baseline screenshot so that the failing test can be unskipped. This test is, unfortunately, very fragile because the font rendering is prone to changing between Chrome updates - however, there isn't really a better way of checking for rendering issues, so we'll have to continue just updating the baseline whenever a failure happens 🙈 ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed: - Flaky test runner: https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/4749 ![image](https://github.com/elastic/kibana/assets/8698078/eeb87dca-4542-4333-af8b-58d07a8c911e) ### 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) --- .../apps/dashboard/group5/embed_mode.ts | 3 +-- .../baseline/dashboard_embed_mode.png | Bin 129613 -> 72266 bytes 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/functional/apps/dashboard/group5/embed_mode.ts b/test/functional/apps/dashboard/group5/embed_mode.ts index fc7b92ab5fb8d..25eabca77f718 100644 --- a/test/functional/apps/dashboard/group5/embed_mode.ts +++ b/test/functional/apps/dashboard/group5/embed_mode.ts @@ -56,8 +56,7 @@ export default function ({ await browser.setWindowSize(1300, 900); }); - // FLAKY: https://github.com/elastic/kibana/issues/163207 - describe.skip('default URL params', () => { + describe('default URL params', () => { it('hides the chrome', async () => { const globalNavShown = await globalNav.exists(); expect(globalNavShown).to.be(true); diff --git a/test/functional/screenshots/baseline/dashboard_embed_mode.png b/test/functional/screenshots/baseline/dashboard_embed_mode.png index 592cd6c4ff4036976b571165fcda8938f93f9d6d..c96c621a8c45b7ca60504c4165adc5cd600d74f8 100644 GIT binary patch literal 72266 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%0DG6TTpPN@Z-E87z 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
    #)ye8M^&|7sV2JkE< zZ1JiQS5JIfa9EIFxWq^^UgMgJi!0@J@pTkMILnSo>4TnVD)YH3w4A)WB)8|pC!@nH z9LU)-ow^$g9~t1xUvodjhI-PjoxJ@UU`xUf_8b)WDA6uJNvN^zTz7qpuPlBf;=BfP*AY<`J5en45DrmOcv3}Z z=1Z~a^F8Uz)bCUZdgs3M1YtfF-n)ES(DzwsjX`Y$k{vn?9(qNv1SmwWsiR)Ye* zQO&CP6>r%sbQZa-Xi+KW@lMzg*6lWL}$eT0iOUw|^o&hG_xv<>lN4@|m4iCFX` zJ1b-<>-{PfmhL0WzclH2$kltb>+@Lr^fzcKMGHef*y!o$6H=r!&p6T%CdV;@d4?BFyXCx%E2>}p zJv~`K5a@!rcfno=u-dAYLAL4E>6rD;cs$x3hhqx?knNN{YHRKr-Te7- zol>_9zeUqTmTLlk$7ROD8;m0-9~s!mw0(>7-U<@M!}M}1f|9%R=e#(e;*|?mP#3lu zQSpAHJmVg!tb&5^cKyRK`-uqM;AlFbOFD-GJvJ|sUNUa8k*h+!!PJ(_R`I(qfhpsV zY;(JCaTxmJP5QL(fm4sROu9f@TVOC~|Mbvk;J2+J)bA+-La7LGVV8-bG#y*7$oc+# zHSK6*={t|*Oh|Vm*#RIv9%oIspn4>vZ+osOxKv-*nMdTKt@w4kvl4K8w9-+FKfiS- z{&1&h_HCXKwtVDw+a!!gp7)!FZK&lzEhm187|;ILVO&~X-k2?7ywly~XmPaGue{bN zf?KvCA|mTE7f;QaF5JF}V*u>f`!M8g4YfUI)f=r4t(vb0hGU6xjwkQ-UH%s z_4Z?6Ab9&AZvyH}Y}_3|_x$;TxW3M+VG$_@hc`?3Ph^#p82I@3w2&CM6lP1JXCHW; zrZ~+vrA38)__cxz6>_9OBo8P0C^dP0aM}5l0;uX*`sCh7?i*|A=pX6!E&3gSxT5!3 z^D@|sy9etmepfRs?=}Wz_}+Z>+HGQopKSgvkQjQ(dww*W4!Sz%iQ>*Uq5=taq?c|? zP{YCCS+!bsvz8tWt(sP&igJe$qu(V+vEgB^mObEz=1fi-_D1tRpxQO;5Y^gDcK5zD zu6S1>!n1<{+8oDRE?{)N&CWEOpR2Y36N2#fD3#B4^^dLvgMxybMmfxJd*+%vxeiaK z^$xEApUGs2So7#d_G`^0?F^JPch3$*CbH_5yG|>MTu#KjY;%I*60>9(wutfA{9LHq zy-P0pqnFae@eWB2u`aYY+1HloGxiT+m7V6?_vR83S<8%;L}80$M{CW>J5%321qC_W zqK-~9f?wF#*@5)L7laIaH^5Pp*m-J6l-qMv!PiJ!hlSQxQ#IBDSJ1s>2Z41!^Mj+w zQ5I6|;g6{@S|i|j+}`J`GkjM>Q?Bdnh!>iN=f*G^oz?zV#aBk8W>qOvelsqw2FD9E zOaTjtVgdiA0E^qym>0_M82)-7B>;^_w%3kyAAvx5xjrptPHGo zzO^^YqI)XX5i}?3>4`2K7y9$3%ABt=@V^*&6qIVK@z{+~Lq;a1&;$3`hXNTP?i=3N zuU@@^mf}5C4Y$?x?OZaW=A@3v@ViM^UymafauGlzZ(W`&UZ15M9qNr2Qq)+Xar^Be zNg|~I3BItIM09rbaC_`Oo2s)9&d8wZp`q2OJXXV@6me;Dm{m#_I=l!=kd(<-iQbuh z_+THg&?W&4I6}bmd2D|r%O^0ehB?2y-D0cHvr(f;ZttD8H=aBsyt658dy^6^zCLW{ zB1e}|AQqiVCNVKF@9K345s?`=dBvq8!WS1Ob@PB~lr)}RDq4*{T8rY$cB+AYlkj@V zmp@#p@5gD<`~EAx^;d-Z{Y=jjtK-I6jEpjExdu1e_31i(z?#*o{Kurw2t#?&t1dGR zn=3QUOt&T~Q1@ESa5Re&PAMA77keUe^33&kk_JxKX>mEtj(cCvrrt$Yh6sdDXKLJgV1isVbS(LfbbCbT+>1n5JZHw30(rS#?l1>!XPLZTHzj**TJiw z;&dBG$C$S=ZD1g0>LmYYSnQUDqHIIDEtE-ISlzN&qjlbb6vEo6VLmZt>!&}j`XVH6ShD0ilG ze_?>VW$k!lR1k^DT%TK2XOzG_A8>peArd{XB^(RPZ)3v(2+;E4BF;-~ZGBKymeR^( zR8jpB5{Qvif59^1b-{)geaK4Qd_yWw)ubZukqsZ&!NCDq|LW`EmAf!s^?(p=#4A`z<3xD|Cq9pnrk^(UycqG}5%$Iv{5pOVs zJHvJBw{y?LK}3t!6NWg_?2)^8Wmw$(aB7SD!hF63T>G|2lY^SNMgR!7hQ9LBKWoiU zN-tgPjmZX(Eg=_+3;K({cwe9j6%WM!nlfDD5-!Jb zo+sM@!NFbu&VoP$1LY!s&xB3_7!3j!44uJ*m#7853M^%$St7Z!Ys1!F9Ltefg06=I z0Do~TEiD^`k+xs??cMrn#m?XJ4W;s~24jn>*2ok7a20KEkOsVr_TjDx0L zVYjQkYc&REz=|aioOiaAi#&21{SQ+b&@{ouNFIO}dL=zabG<>u!6{QNNq zNpjIOXSRKw0zwHeGF)O8E~Irc-lI~>;FU#7#YQg?GJadL(*~-?M4CzT;lvBOyWPgo zqKbfpY}{XZ@kvHpR8;49B$meYUo%a2_~X3M#( z-bX`LEJT>NZ@m0d?I|^<{=js4wVyiaBBYIBah3w97E?QJSJ&POg6*;YOq}(pb4A39 z!R)qDrvw@$?m~B!wKHC%D-8FNu<}eqg%Ld|(X@trK@1KmzP28BIAFa4E@UkQo=}FS zrs_f@Al%&C1^7?(`tkli$S*!og|`n4v6}Z*P1?YiSnipanXCvkmrFp7^j9zBDK7!T zMWgz5HDQ_Q4~kOY5yss!prNA9b%)r-ck3q@0r6ou68+#0XOFwoN!ofoS`0-x8uJC<+{<^efavTm4jsGHR&~`n6k6l0n-i^Ka zD)4HUiv$!bakov!5?jVwBi9vWas|QA)DguHcV4@~(YV|jR|R37|IpC4dNoPF?v{hv zkz&jn3>0GO2fOiw&s%&31d?4Mu)G-Leyg7{kgr|n9|W!6cX3 zA%zI80>4Gu4YV2!Yi zw&Vul>^ppN>51F6IlpiuBy&2S;{vRYvH7z>1rkox z4(cTd9=p*zT* z+B`@s9CW&oY7=bh&5600= z8XEmmwOT=EVlJZ<59tW<;WQ|w0zLX2|0)Y*%3eukh@iDr%RrV67&BTHl6CDH;#%DI zSWmT?-_4n^?SLdpd34-f^o%MQy9+!xEsRJVQ3dKt^@`D(TE?7TFMvY=@M98e*d(7_ z$#g2m{K79BWoCc+43<3iJxUKRucY1+1E1?VO|u-$)hOL5f)|?))Mn`X@L&V@ghA<@ zR{o=AV>-_~w9~cJQjHO%+@}Zjq^0&w6~TwsxMUk(TmH-A-M7r}GFfn{=ku`m$HH!j zsK6@=mq2OXwmEop2GQWE4bxnoomhv$fN5q_uy~%E)6i~}Mr4o?64dBnvc?;W^ z>l@Xs^F__xOYYqm<%}Q~4UnSpx%X1uidp$)PpWiBG=wZT(q#4$TM)4$?(n5znPH^v zR%MrjKh(G<3Uz<7l08{u6%X`lbQHY!9WDsobb)Z5ZcawJ&-q67zY2iX`W>t?Gt4>@ z1J3z7khIKjJCXyS+YgnqJ!WpRA+zq{$?s0Kcc-h zs(*S+;%&~S;>fGd8a=i57K~3jO*mq{Bn*D-&3NE)WU3+ySB+BX%F_y%nyj}Z zGi15FLm_sX&6(TUcu9V?up2-i+p`VPWXszYn?Sh?7(*CqWfgd@?~%Vo8wOsi_G;UuEP8Vd+n z+Gb}dK;d1H@(K6qea1ZONX9aRrK4Nna7M=NTHALBQsiQXjO9p{B@79K0Z!{bV_y3u zO7VWUqEIC9lLrJ%PCo%LIj->#%k zP*@GsZy~NvcQlq++Sz%dqVmi=l5A+|MEu^*1}%3!yE*jM-?lA3oAt>W8%5X!#DS#m zO==yd?IzvK49i$4Mf<|5>&g0&i~a7UHEBsnI!nt9tmY4(<-Mn-JJY?75AsY*R$5|9X6+a`IUgEkRDG5aH>7&<1Rp38pf&qxO*H#3 zI2;#myDV?PBUoHUS*5ETm-@Flc^fKQa8}#lz59s}J=+1Ydxcc8(J%@Xt zXZq@G!F5_?2CN9zl6SnJf)uDP%M3&(s{3?QW~#xu&CWBOU0rbyNZZ15U9j!SHk zZu0@n*yQ;8t(e1NZM&kk92WZy49eh7s2Dh_WC}0+#npBjQZe$BmS)e^D%@sqFDR{f zo*tZ>P%~X@XK{tf^_?RxKJX;kSk?ISD0zGP>>r#IJa#_#OP<&r4yG*Lt!v-XvjIf& za`_hERG_jK|CqfB!?G4D>zC03r!$OaT&r}T=EQdQaU!O096Acx4v17{1N)pAF38GL zgW=~;^!l+jAP8AHFSVIum`uA4^6}4+NR-ETcycPM&p-g$5Ik#geQ1fe>mg zO)x!*V#E{?v8yui?0onlm-Gab&*9w_oG-C@1Ag}R^Z$)x!Jj)5=~ z*fPvs@Pn{w*MC}BAuuvBO5wkyy*z>PnH!ctX2HhYw9YPav2H#^LRy-Ele0qc>mf(WbuC5Fc>m8-8OMcIY9J)Nx$y;ZBGBpfY!AHXH|TxM zyOhJ$Y?15j7c(6B;^D;2etkwXtqX0a9%t7V{T>Vw2gvIn>CM$* zJH4cgFx9h?TVGl~8~0frV%t(XDJNB~KDoYX=#TO5$^hf>m>BgEoY%|;*YP?#JDtvZ zM`-Fa9uu5hp){9 z@^=-tS?hTtZp@WJBIx}fl5G6NYQvW>n2F1c1RvK4K{$?YYSpX}kF)Nq*muIj5Cwpx zBuo0d@Kd6jlL;3ij26gLM>;n8qUquD$o))}7-G zA68oFSt)sW=8m8l0Pcd_=u9-2yA!d!>sMeGN!UvB+JlA@8-fD?PH;N5YePJjsB>HR z!hKPLKJcZG2$WOVPE`Zl9Ztiu%O2}7w=rpHuXm=XMNT>;KmZDz#H#DJ81(A8VshJM zcPt=9!oJmp&Ep-<`sJ2@lR( zqeR>L81O;&illa{(Og2?srcJZ>VV-~@hJ^IGMYEAD5HA`+N0rp>>ZgzJMwLJFO&*~8+ee=2E0XYk%*SWcsrL}XRZf@neobTFgrpu86|8xAMEO0}bP3cbIvaM|ozt#O zSn-)Y7;eOwZ23ebn8zCZmi}`f>YRl;6*b~y?Fmy^w~Y@32o2BpelVH$I@cyFrV4x^ zXq&i1-O#EsW|CSL!U3rPXyj5L{r|F!0Wnot>1F^mt1= zVtk%u*!dNa<5zBXYO>)${>f}Fgtr!sivT%@{9$ybQN??%6sJSVhS?~9?iVk@f7A^4 zMqflkD6VB9m7Ej!kokD{P9$sZHhS= z6H@`p)w#1$Pv^lP{uy!pY&eB;Mey2W*mB#C!}oU(cvre}V$R1k+oZ!GcQU6YDi8f( zk!azkj^yE8A5&Aw7~&oRiDujT-adXVZZ5X1%SqyU8?S z2&9{rqSS1a88Kg>TYDWvAffnsIx4v+$>(4SkL}0X~486tDtz9Cs3Pv~NSvy0pelrcv{cLq+ z)U)DV2CC(j*f|nr*zA<6-8)YuhWLhHFhm>oRkAC1yE*}p*hgkqS{09aPGiYy0s{NS zZ|vOjkbyB7!v(-4R9i253y~9Nyi{43%&Q4NxuK(Dz{e+3PUsI1oG#LQNW;L^+_{_> z#>hY$0Pyi}YPV}}2KkWcsxFq)D+%;dydK{bR_uwX($h1Ebl2LxQ4Q7T9KQ*5hus+> z*5T_DZ>vR1Cq@zauM&MR^rTqn!DQZs>W=4}w(t1! z^izvK`5IM1eR51MZ*XHVPWSp+Z$vqt!g8CMo5cWZ7v;;>M1ZBr5P0R}4gj|N+GIB8 zEQiUI%)*vOPT#U6%Q^S;&B9ccyyBs?^$>{;SU!`o|=q+Qfh~ ziV`vb7TNhZo53X-?wmWZs}+1{Kx6CN?wSGpbhu$4&soe3Bj~8kuv{v~;gnH&f2I_y zO;M{ijr}q;vztfU-gNp$Gw*gO85gd z+g!FxsU9XmD}t_w4v71DOmUN#$~Hfb!@y0x9hy^mJ1lH#XV0Lj{_|+IE_+h}NrtII zXJoZT?gAc5i;Z57=olE(3S#|WNI<+plx6Qf<9-p&-lEfU9k*-J(QQi{IXN&OIQZk) z4$(^T)ozW%v}U!%@Aa&n&d%=9^0vt|I%Jz?VE9}B;G+pNqz0z@eO_@=b3V)-k=52m zY>Lk|xV>+a86cf#VMMv{1qP`J=090bEcW*Cc~DHy+BaGOQ~`+n)$)ujXH>!~Wk*;9 z8;OcKr1dkt9v4go@K_6NMcvA~c(SCN7Gp-?x*T=Dx20lv6M&SlU`y>3@q!SVyp5)_ zc|O*AmaG|oeSUIG$tQE$x9*8rPBL(9C_$qtUwd;b3|P2o%UO|mW2_4ic7u!Ycb+ag zvcr_=6HRA^h>i^=_X@LF=~^2kw*PO|)R6}BByTDqzp6`&6=(eAq+w2(K#y)p`# zpoP7?o@`vD!DSm66iPGVmEFBu5>RE650q~*zHS{(q?JR|{+410^`lEfI zIE*Y%?Gj9bx)!Zn?JsNEHCa9uzMWFAkmX>=j`>~kwaTOKkx;d*+-svJK>gKtus2oy zLMf+F_{(}4-6=%6!K)i2Ka|<8EwM=YwZ@KxB z`6cdX~`1;_pZ`KDc!ecuv^`? z_+!&z!zOLoM@Q3%hMpcBI!EjA_==0qdr!0WauPRarOrn6S&Rj`-i0fgtG+l=Rg;71 z+4hS=?qVyU=7#2o`CEs9@&J&_-Y>}cCpt>-p=tBA9V$Qe2Ce{N+H$;-R9WOmhDCgY z8-$Z1Rn?95BRIT9_lxmi1Kb&*GPsv~cb?z@b^ymTGFldJIwtvmz@i0g0v=O{)4T*; zrf-vw$l2H!W^L+_*)AnN&9F1f?;fivfmvYaOMY=9Zv2abPPa=8!$1mQG9?>~XRS-A z2r#udk>v&B;serC#hFMuFeRhv@13C(@q;C_E(%Vhz*q9mD5y6?_Mj(~s^@DHnm{`1 z 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 From 5fa14686e5c6b3edffb338c3029a46a4316fdfca Mon Sep 17 00:00:00 2001 From: Paul Tavares <56442535+paul-tavares@users.noreply.github.com> Date: Thu, 4 Jan 2024 10:22:41 -0500 Subject: [PATCH 016/100] [Security solution][Endpoint] Additional changes to response action APIs in support of SentinelOne (#173882) ## Summary PR makes additional changes to Endpoint (kibana) response action APIs in support of 3rd party EDR systems and support for SentinelOne. Changes include: - `release` response action support for SentinelOne - Action responses for SentinelOne `isolate` and `release` are now written to the responses index (thanks to [this PR](https://github.com/elastic/elasticsearch/pull/103555)) - Action Details and List APIs now return `agentType` and support 3rd party EDR response actions - SentinelOne response actions are now returned and in the expected state (completed) - Added feature usage reporting to response actions client base class (sent when action request is written to ES index) - Added method to SentinelOne actions client to retrieve agent details - Host name for SentinelOne is now stored along with the Action Request document - Refactored action details and action list services to use common methods for: - fetching the action responses from ES - building the `ActionDetails` record for each action - Made several types (mostly around response action responses) to be generic to provided the ability to narrow the `output` type --- .../endpoint_action_generator.ts | 70 ++++-- .../service/response_actions/type_guards.ts | 40 +++ .../common/endpoint/types/actions.ts | 56 ++++- .../common/endpoint/types/index.ts | 1 + .../common/endpoint/types/utility_types.ts | 21 ++ .../endpoint_action_failure_message.tsx | 2 +- .../execute_action_host_response.test.tsx | 18 +- .../execute_action_host_response.tsx | 5 +- .../execute_action.tsx | 20 +- .../components/action_success.tsx | 2 +- .../hooks/use_console_action_submitter.tsx | 30 +-- .../components/endpoint_responder/types.ts | 5 +- .../components/action_log_expanded_tray.tsx | 19 +- .../use_get_action_details.ts | 14 +- .../use_get_automated_action_list.ts | 1 + .../endpoint/common/response_actions.ts | 49 ++-- .../server/endpoint/mocks.ts | 3 +- .../routes/actions/response_actions.test.ts | 3 +- .../routes/actions/response_actions.ts | 4 +- .../endpoint/routes/actions/status.test.ts | 3 + .../actions/action_details_by_id.test.ts | 2 + .../services/actions/action_details_by_id.ts | 70 +----- .../services/actions/action_list.test.ts | 45 ++-- .../endpoint/services/actions/action_list.ts | 55 +---- .../clients/endpoint_actions_client.ts | 11 +- .../services/actions/clients/errors.ts | 4 +- .../get_response_actions_client.test.ts | 3 +- .../lib/base_response_actions_client.test.ts | 36 ++- .../lib/base_response_actions_client.ts | 48 +++- .../services/actions/clients/mocks.ts | 37 +-- .../actions/clients/sentinelone/mock.ts | 177 +++++++++++++ .../sentinel_one_actions_client.test.ts | 143 +++++++++-- .../sentinel_one_actions_client.ts | 120 +++++++-- .../actions/clients/sentinelone/types.ts | 26 ++ .../endpoint/services/actions/create/index.ts | 20 +- .../endpoint/services/actions/create/types.ts | 3 +- .../actions/create/write_action_to_indices.ts | 6 +- .../actions/fetch_action_responses.test.ts | 232 ++++++++++++++++++ .../actions/fetch_action_responses.ts | 89 +++++++ .../server/endpoint/services/actions/mocks.ts | 14 +- .../endpoint/services/actions/utils.test.ts | 150 ++++++++++- .../server/endpoint/services/actions/utils.ts | 90 ++++++- .../services/feature_usage/feature_keys.ts | 48 ++++ .../endpoint/services/feature_usage/index.ts | 2 +- .../endpoint/services/feature_usage/mocks.ts | 2 + .../services/feature_usage/service.ts | 36 +-- .../utils/action_list_helpers.test.ts | 130 +--------- .../endpoint/utils/action_list_helpers.ts | 65 +---- .../endpoint/utils/{dump.ts => stringify.ts} | 2 +- .../endpoint/validators/base_validator.ts | 2 +- 50 files changed, 1448 insertions(+), 586 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/endpoint/service/response_actions/type_guards.ts create mode 100644 x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/mock.ts create mode 100644 x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/types.ts create mode 100644 x-pack/plugins/security_solution/server/endpoint/services/actions/fetch_action_responses.test.ts create mode 100644 x-pack/plugins/security_solution/server/endpoint/services/actions/fetch_action_responses.ts create mode 100644 x-pack/plugins/security_solution/server/endpoint/services/feature_usage/feature_keys.ts rename x-pack/plugins/security_solution/server/endpoint/utils/{dump.ts => stringify.ts} (88%) diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/endpoint_action_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/endpoint_action_generator.ts index 03f769e34c5d8..f3f9bde438d68 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_generators/endpoint_action_generator.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_generators/endpoint_action_generator.ts @@ -26,6 +26,8 @@ import type { ResponseActionExecuteOutputContent, ResponseActionUploadOutputContent, ResponseActionUploadParameters, + EndpointActionResponseDataOutput, + WithAllKeys, } from '../types'; import { ActivityLogItemTypes } from '../types'; import { @@ -75,9 +77,11 @@ export class EndpointActionGenerator extends BaseDataGenerator { } /** Generates an endpoint action response */ - generateResponse( - overrides: DeepPartial = {} - ): LogsEndpointActionResponse { + generateResponse< + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput + >( + overrides: DeepPartial> = {} + ): LogsEndpointActionResponse { const timeStamp = overrides['@timestamp'] ? new Date(overrides['@timestamp']) : new Date(); const startedAtTimes: number[] = []; @@ -91,7 +95,7 @@ export class EndpointActionGenerator extends BaseDataGenerator { const command = overrides?.EndpointActions?.data?.command ?? this.randomResponseActionCommand(); let output: ActionResponseOutput< ResponseActionGetFileOutputContent | ResponseActionExecuteOutputContent - > = overrides?.EndpointActions?.data?.output as ActionResponseOutput< + > = overrides?.EndpointActions?.data?.output as unknown as ActionResponseOutput< ResponseActionGetFileOutputContent | ResponseActionExecuteOutputContent >; @@ -168,7 +172,7 @@ export class EndpointActionGenerator extends BaseDataGenerator { error: undefined, }, overrides - ); + ) as LogsEndpointActionResponse; } generateResponseEsHit( @@ -180,13 +184,15 @@ export class EndpointActionGenerator extends BaseDataGenerator { } generateActionDetails< - TOutputType extends object = object, + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput, TParameters extends EndpointActionDataParameterTypes = EndpointActionDataParameterTypes >( - overrides: DeepPartial> = {} - ): ActionDetails { - const details: ActionDetails = { + overrides: DeepPartial> = {} + ): ActionDetails { + const details: WithAllKeys = { + action: '123', agents: ['agent-a'], + agentType: 'endpoint', command: 'isolate', completedAt: '2022-04-30T16:08:47.449Z', hosts: { 'agent-a': { name: 'Host-agent-a' } }, @@ -209,6 +215,9 @@ export class EndpointActionGenerator extends BaseDataGenerator { wasSuccessful: true, }, }, + alertIds: undefined, + ruleId: undefined, + ruleName: undefined, }; const command = overrides.command ?? details.command; @@ -216,7 +225,7 @@ export class EndpointActionGenerator extends BaseDataGenerator { if (command === 'get-file') { if (!details.parameters) { ( - details as ActionDetails< + details as unknown as ActionDetails< ResponseActionGetFileOutputContent, ResponseActionGetFileParameters > @@ -226,14 +235,26 @@ export class EndpointActionGenerator extends BaseDataGenerator { } if (!details.outputs || Object.keys(details.outputs).length === 0) { - details.outputs = { + ( + details as unknown as ActionDetails< + ResponseActionGetFileOutputContent, + ResponseActionGetFileParameters + > + ).outputs = { [details.agents[0]]: { type: 'json', content: { code: 'ra_get-file_success', - path: '/some/file/txt', - size: 1234, zip_size: 123, + contents: [ + { + path: '/some/file/txt', + sha256: '1254', + size: 1234, + file_name: 'some-file.txt', + type: 'file', + }, + ], }, }, }; @@ -243,7 +264,7 @@ export class EndpointActionGenerator extends BaseDataGenerator { if (command === 'execute') { if (!details.parameters) { ( - details as ActionDetails< + details as unknown as ActionDetails< ResponseActionExecuteOutputContent, ResponseActionsExecuteParameters > @@ -256,7 +277,12 @@ export class EndpointActionGenerator extends BaseDataGenerator { } if (!details.outputs || Object.keys(details.outputs).length === 0) { - details.outputs = { + ( + details as unknown as ActionDetails< + ResponseActionExecuteOutputContent, + ResponseActionsExecuteParameters + > + ).outputs = { [details.agents[0]]: this.generateExecuteActionResponseOutput({ content: { output_file_id: getFileDownloadId(details, details.agents[0]), @@ -268,7 +294,7 @@ export class EndpointActionGenerator extends BaseDataGenerator { } if (command === 'upload') { - const uploadActionDetails = details as ActionDetails< + const uploadActionDetails = details as unknown as ActionDetails< ResponseActionUploadOutputContent, ResponseActionUploadParameters >; @@ -293,7 +319,7 @@ export class EndpointActionGenerator extends BaseDataGenerator { } return merge(details, overrides as ActionDetails) as unknown as ActionDetails< - TOutputType, + TOutputContent, TParameters >; } @@ -328,9 +354,11 @@ export class EndpointActionGenerator extends BaseDataGenerator { ); } - generateActivityLogActionResponse( - overrides: DeepPartial - ): EndpointActivityLogActionResponse { + generateActivityLogActionResponse< + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput + >( + overrides: DeepPartial> + ): EndpointActivityLogActionResponse { return merge( { type: ActivityLogItemTypes.RESPONSE, @@ -359,7 +387,7 @@ export class EndpointActionGenerator extends BaseDataGenerator { } generateExecuteActionResponseOutput( - overrides?: Partial>> + overrides?: DeepPartial> ): ActionResponseOutput { return merge( { diff --git a/x-pack/plugins/security_solution/common/endpoint/service/response_actions/type_guards.ts b/x-pack/plugins/security_solution/common/endpoint/service/response_actions/type_guards.ts new file mode 100644 index 0000000000000..7786c9ebb1f57 --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/service/response_actions/type_guards.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { + ActionDetails, + MaybeImmutable, + ResponseActionExecuteOutputContent, + ResponseActionsExecuteParameters, + ResponseActionUploadOutputContent, + ResponseActionUploadParameters, + ResponseActionGetFileOutputContent, + ResponseActionGetFileParameters, +} from '../../types'; + +type SomeObjectWithCommand = Pick; + +export const isUploadAction = ( + action: MaybeImmutable +): action is ActionDetails => { + return action.command === 'upload'; +}; + +export const isExecuteAction = ( + action: MaybeImmutable +): action is ActionDetails< + ResponseActionExecuteOutputContent, + ResponseActionsExecuteParameters +> => { + return action.command === 'execute'; +}; + +export const isGetFileAction = ( + action: MaybeImmutable +): action is ActionDetails => { + return action.command === 'get-file'; +}; diff --git a/x-pack/plugins/security_solution/common/endpoint/types/actions.ts b/x-pack/plugins/security_solution/common/endpoint/types/actions.ts index f2393c02c3b41..9b89954ee6974 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/actions.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/actions.ts @@ -23,7 +23,9 @@ import type { export type ISOLATION_ACTIONS = 'isolate' | 'unisolate'; /** The output provided by some of the Endpoint responses */ -export interface ActionResponseOutput { +export interface ActionResponseOutput< + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput +> { type: 'json' | 'text'; content: TOutputContent; } @@ -36,6 +38,7 @@ export interface ProcessesEntry { } export interface GetProcessesActionOutputContent { + code: string; entries: ProcessesEntry[]; } @@ -96,7 +99,7 @@ export const ActivityLogItemTypes = { interface EndpointActionFields< TParameters extends EndpointActionDataParameterTypes = EndpointActionDataParameterTypes, - TOutputContent extends object = object + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput > { action_id: string; data: EndpointActionData; @@ -146,7 +149,9 @@ export interface LogsEndpointActionWithHosts extends LogsEndpointAction { * An Action response written by the endpoint to the Endpoint `.logs-endpoint.action.responses` datastream * @since v7.16 */ -export interface LogsEndpointActionResponse { +export interface LogsEndpointActionResponse< + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput +> { '@timestamp': string; agent: { id: string | string[]; @@ -155,6 +160,7 @@ export interface LogsEndpointActionResponse, 'comment' | 'command' | 'output'>; + input_type: ResponseActionAgentType; }; error?: EcsError; } @@ -189,9 +195,19 @@ export type EndpointActionDataParameterTypes = | ResponseActionGetFileParameters | ResponseActionUploadParameters; +/** Output content of the different response actions */ +export type EndpointActionResponseDataOutput = + | Record // Empty object + | ResponseActionExecuteOutputContent + | ResponseActionGetFileOutputContent + | ResponseActionUploadOutputContent + | GetProcessesActionOutputContent + | SuspendProcessActionOutputContent + | KillProcessActionOutputContent; + export interface EndpointActionData< TParameters extends EndpointActionDataParameterTypes = EndpointActionDataParameterTypes, - TOutputContent extends object = object + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput > { command: ResponseActionsApiCommandNames; comment?: string; @@ -226,6 +242,10 @@ export interface EndpointAction extends ActionRequestFields { }; } +/** + * The action response created in Fleet's index after the action has been successfully delivered to + * the endpoint + */ export interface EndpointActionResponse { '@timestamp': string; /** The id of the action for which this response is associated with */ @@ -250,11 +270,13 @@ export interface EndpointActivityLogAction { }; } -export interface EndpointActivityLogActionResponse { +export interface EndpointActivityLogActionResponse< + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput +> { type: typeof ActivityLogItemTypes.RESPONSE; item: { id: string; - data: LogsEndpointActionResponse; + data: LogsEndpointActionResponse; }; } @@ -306,9 +328,11 @@ export interface HostIsolationResponse { } export type ProcessesRequestBody = TypeOf; -export interface ResponseActionApiResponse { +export interface ResponseActionApiResponse< + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput +> { action?: string; - data: ActionDetails; + data: ActionDetails; } export interface EndpointPendingActions { @@ -334,11 +358,17 @@ export interface ActionDetailsAgentState { } export interface ActionDetails< - TOutputContent extends object = object, + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput, TParameters extends EndpointActionDataParameterTypes = EndpointActionDataParameterTypes > { - /** The action id passed only if returnActionIdCommands contains the command */ + /** + * The action ID. This is a legacy property action and should no longer be used. Only here for + * backwards compatibility + * + * @deprecated + */ action?: string; + /** The action id */ id: string; /** @@ -389,13 +419,15 @@ export interface ActionDetails< alertIds?: string[]; ruleId?: string; ruleName?: string; + /** The agent type to where the response action was sent */ + agentType: ResponseActionAgentType; } export interface ActionDetailsApiResponse< - TOutputType extends object = object, + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput, TParameters extends EndpointActionDataParameterTypes = EndpointActionDataParameterTypes > { - data: ActionDetails; + data: ActionDetails; } /** Action Details normally returned by Action List API response */ diff --git a/x-pack/plugins/security_solution/common/endpoint/types/index.ts b/x-pack/plugins/security_solution/common/endpoint/types/index.ts index 8f195b926e1f0..4887d83493f5c 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/index.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/index.ts @@ -12,6 +12,7 @@ import type { ManifestSchema } from '../schema/manifest'; export * from './actions'; export * from './os'; export * from './trusted_apps'; +export * from './utility_types'; export type { ConditionEntriesMap, ConditionEntry } from './exception_list_items'; /** diff --git a/x-pack/plugins/security_solution/common/endpoint/types/utility_types.ts b/x-pack/plugins/security_solution/common/endpoint/types/utility_types.ts index a70c8e124eb84..2fd25a2cc37d5 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/utility_types.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/utility_types.ts @@ -17,3 +17,24 @@ export type PromiseResolvedValue> = T extends Promise = T extends Record ? { -readonly [K in keyof T]: DeepMutable } : T; + +/** + * Ensure that a given type includes all of its key, even if they are optional (value can still be `undefined`) + * + * @example + * interface Foo { + * one?: number; + * two: number; + * } + * const missingKeys: Foo = { two: 2 }; // ok + * + * const shouldHaveAllKeys: WithAllKeys = { two: 2 }; // TS Error + * + * const withAllKeys: WithAllKeys = { + * one: undefined, // All good now + * two: 2 + * } + */ +export type WithAllKeys = { + [k in keyof Required]: T[k]; +}; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_action_failure_message/endpoint_action_failure_message.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_action_failure_message/endpoint_action_failure_message.tsx index 7e85a0d081ed6..f9f982188ffa4 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_action_failure_message/endpoint_action_failure_message.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_action_failure_message/endpoint_action_failure_message.tsx @@ -13,7 +13,7 @@ import { endpointActionResponseCodes } from '../endpoint_responder/lib/endpoint_ import type { ActionDetails, MaybeImmutable } from '../../../../common/endpoint/types'; interface EndpointActionFailureMessageProps { - action: MaybeImmutable>; + action: MaybeImmutable; 'data-test-subj'?: string; } diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_execute_action/execute_action_host_response.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_execute_action/execute_action_host_response.test.tsx index 04958e60b4de8..a16f1f2007f57 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_execute_action/execute_action_host_response.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_execute_action/execute_action_host_response.test.tsx @@ -10,6 +10,7 @@ import type { ResponseActionExecuteOutputContent, ResponseActionsExecuteParameters, ActionDetails, + DeepMutable, } from '../../../../common/endpoint/types'; import React from 'react'; import { EndpointActionGenerator } from '../../../../common/endpoint/data_generators/endpoint_action_generator'; @@ -23,8 +24,8 @@ import { EXECUTE_OUTPUT_FILE_TRUNCATED_MESSAGE } from './execute_action_host_res describe('When using the `ExecuteActionHostResponse` component', () => { let render: () => ReturnType; let renderResult: ReturnType; - let renderProps: ExecuteActionHostResponseProps; - let action: ActionDetails; + let renderProps: DeepMutable; + let action: DeepMutable['action']; beforeEach(() => { const appTestContext = createAppRootMockRenderer(); @@ -32,7 +33,10 @@ describe('When using the `ExecuteActionHostResponse` component', () => { action = new EndpointActionGenerator('seed').generateActionDetails< ResponseActionExecuteOutputContent, ResponseActionsExecuteParameters - >({ command: 'execute', agents: ['agent-a'] }); + >({ + command: 'execute', + agents: ['agent-a'], + }); renderProps = { action, @@ -92,11 +96,11 @@ describe('When using the `ExecuteActionHostResponse` component', () => { }); it('should show `-` in output accordion when no output content', async () => { - (renderProps.action as ActionDetails).outputs = { + renderProps.action.outputs = { 'agent-a': { type: 'json', content: { - ...(renderProps.action as ActionDetails).outputs?.[action.agents[0]].content, + ...renderProps.action.outputs![action.agents[0]].content, stdout: '', }, }, @@ -109,11 +113,11 @@ describe('When using the `ExecuteActionHostResponse` component', () => { }); it('should NOT show the error accordion when no error content', async () => { - (renderProps.action as ActionDetails).outputs = { + renderProps.action.outputs = { 'agent-a': { type: 'json', content: { - ...(renderProps.action as ActionDetails).outputs?.[action.agents[0]].content, + ...renderProps.action.outputs![action.agents[0]].content, stderr: '', }, }, diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_execute_action/execute_action_host_response.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_execute_action/execute_action_host_response.tsx index 3c7b5818907ac..43ff3ffca5a62 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_execute_action/execute_action_host_response.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_execute_action/execute_action_host_response.tsx @@ -10,13 +10,16 @@ import type { ActionDetails, MaybeImmutable, ResponseActionExecuteOutputContent, + ResponseActionsExecuteParameters, } from '../../../../common/endpoint/types'; import { EXECUTE_FILE_LINK_TITLE } from '../endpoint_response_actions_list/translations'; import { ResponseActionFileDownloadLink } from '../response_action_file_download_link'; import { ExecuteActionHostResponseOutput } from './execute_action_host_response_output'; export interface ExecuteActionHostResponseProps { - action: MaybeImmutable; + action: MaybeImmutable< + ActionDetails + >; agentId?: string; canAccessFileDownloadLink: boolean; 'data-test-subj'?: string; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/execute_action.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/execute_action.tsx index 8192b6a08b07c..7e19a03860013 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/execute_action.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/execute_action.tsx @@ -11,17 +11,24 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { ExecuteActionRequestBody } from '../../../../../common/api/endpoint'; import { useConsoleActionSubmitter } from '../hooks/use_console_action_submitter'; -import type { ResponseActionExecuteOutputContent } from '../../../../../common/endpoint/types'; +import type { + ResponseActionExecuteOutputContent, + ResponseActionsExecuteParameters, +} from '../../../../../common/endpoint/types'; import { useSendExecuteEndpoint } from '../../../hooks/response_actions/use_send_execute_endpoint_request'; import type { ActionRequestComponentProps } from '../types'; import { parsedExecuteTimeout } from '../lib/utils'; import { ExecuteActionHostResponse } from '../../endpoint_execute_action'; export const ExecuteActionResult = memo< - ActionRequestComponentProps<{ - command: string; - timeout?: string; - }> + ActionRequestComponentProps< + { + command: string; + timeout?: string; + }, + ResponseActionExecuteOutputContent, + ResponseActionsExecuteParameters + > >(({ command, setStore, store, status, setStatus, ResultComponent }) => { const actionCreator = useSendExecuteEndpoint(); const actionRequestBody = useMemo(() => { @@ -47,7 +54,8 @@ export const ExecuteActionResult = memo< const { result, actionDetails: completedActionDetails } = useConsoleActionSubmitter< ExecuteActionRequestBody, - ResponseActionExecuteOutputContent + ResponseActionExecuteOutputContent, + ResponseActionsExecuteParameters >({ ResultComponent, setStore, diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/action_success.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/action_success.tsx index 9f7a22ece8721..ff495096dcbf6 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/action_success.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/action_success.tsx @@ -11,7 +11,7 @@ import type { ActionDetails, MaybeImmutable } from '../../../../../common/endpoi import type { CommandExecutionResultComponent, CommandExecutionResultProps } from '../../console'; export interface ActionSuccessProps extends CommandExecutionResultProps { - action: MaybeImmutable>; + action: MaybeImmutable; ResultComponent: CommandExecutionResultComponent; } diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/hooks/use_console_action_submitter.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/hooks/use_console_action_submitter.tsx index 519072b0fd258..08c2907dde0e3 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/hooks/use_console_action_submitter.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/hooks/use_console_action_submitter.tsx @@ -22,11 +22,12 @@ import type { Immutable, ResponseActionApiResponse, EndpointActionDataParameterTypes, + EndpointActionResponseDataOutput, } from '../../../../../common/endpoint/types'; import type { CommandExecutionComponentProps } from '../../console'; export interface ConsoleActionSubmitter< - TActionOutputContent extends object = object, + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput, TParameters extends EndpointActionDataParameterTypes = EndpointActionDataParameterTypes > { /** @@ -34,14 +35,14 @@ export interface ConsoleActionSubmitter< * including pending, error conditions and generic success messages. */ result: JSX.Element; - actionDetails: Immutable> | undefined; + actionDetails: Immutable> | undefined; } /** * Command store state for response action api state. */ export interface CommandResponseActionApiState< - TActionOutputContent extends object = object, + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput, TParameters extends EndpointActionDataParameterTypes = EndpointActionDataParameterTypes > { actionApiState?: { @@ -50,20 +51,20 @@ export interface CommandResponseActionApiState< actionId: string | undefined; error: IHttpFetchError | undefined; }; - actionDetails: ActionDetails | undefined; + actionDetails: ActionDetails | undefined; actionDetailsError: IHttpFetchError | undefined; }; } export interface UseConsoleActionSubmitterOptions< TReqBody extends BaseActionRequestBody = BaseActionRequestBody, - TActionOutputContent extends object = object, + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput, TParameters extends EndpointActionDataParameterTypes = EndpointActionDataParameterTypes > extends Pick< CommandExecutionComponentProps< // eslint-disable-next-line @typescript-eslint/no-explicit-any any, - CommandResponseActionApiState + CommandResponseActionApiState >, 'ResultComponent' | 'setStore' | 'store' | 'status' | 'setStatus' > { @@ -99,7 +100,7 @@ export interface UseConsoleActionSubmitterOptions< */ export const useConsoleActionSubmitter = < TReqBody extends BaseActionRequestBody = BaseActionRequestBody, - TActionOutputContent extends object = object, + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput, TParameters extends EndpointActionDataParameterTypes = EndpointActionDataParameterTypes >({ actionCreator, @@ -112,18 +113,17 @@ export const useConsoleActionSubmitter = < dataTestSubj, pendingMessage, successMessage, -}: UseConsoleActionSubmitterOptions< - TReqBody, - TActionOutputContent, +}: UseConsoleActionSubmitterOptions): ConsoleActionSubmitter< + TOutputContent, TParameters ->): ConsoleActionSubmitter => { +> => { const isMounted = useIsMounted(); const getTestId = useTestIdGenerator(dataTestSubj); const isPending = status === 'pending'; const currentActionState = useMemo< Immutable< - Required>['actionApiState'] + Required>['actionApiState'] > >( () => @@ -147,7 +147,7 @@ export const useConsoleActionSubmitter = < } = currentActionState.request; const { data: apiActionDetailsResponse, error: apiActionDetailsError } = useGetActionDetails< - TActionOutputContent, + TOutputContent, TParameters >(actionId ?? '-', { enabled: Boolean(actionId) && isPending, @@ -158,11 +158,11 @@ export const useConsoleActionSubmitter = < useEffect(() => { if (!actionRequestSent && actionRequestBody && isMounted()) { const updatedRequestState: Required< - CommandResponseActionApiState + CommandResponseActionApiState >['actionApiState']['request'] = { ...( currentActionState as Required< - CommandResponseActionApiState + CommandResponseActionApiState >['actionApiState'] ).request, sent: true, diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/types.ts b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/types.ts index d74cd7948d811..c2277576ff63a 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/types.ts +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/types.ts @@ -10,6 +10,7 @@ import type { ManagedConsoleExtensionComponentProps } from '../console'; import type { HostMetadata, EndpointActionDataParameterTypes, + EndpointActionResponseDataOutput, } from '../../../../common/endpoint/types'; import type { CommandExecutionComponentProps } from '../console/types'; @@ -23,10 +24,10 @@ export type EndpointResponderExtensionComponentProps = ManagedConsoleExtensionCo export type ActionRequestComponentProps< TArgs extends object = object, - TActionOutputContent extends object = object, + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput, TParameters extends EndpointActionDataParameterTypes = EndpointActionDataParameterTypes > = CommandExecutionComponentProps< { comment?: string } & TArgs, - CommandResponseActionApiState, + CommandResponseActionApiState, EndpointCommandDefinitionMeta >; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/action_log_expanded_tray.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/action_log_expanded_tray.tsx index b70a74d839bc9..aef96add08813 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/action_log_expanded_tray.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/action_log_expanded_tray.tsx @@ -9,6 +9,11 @@ import React, { memo, useMemo } from 'react'; import { EuiCodeBlock, EuiDescriptionList, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { css, euiStyled } from '@kbn/kibana-react-plugin/common'; import { map } from 'lodash'; +import { + isExecuteAction, + isGetFileAction, + isUploadAction, +} from '../../../../../common/endpoint/service/response_actions/type_guards'; import { EndpointUploadActionResult } from '../../endpoint_upload_action_result'; import { useUserPrivileges } from '../../../../common/components/user_privileges'; import { OUTPUT_MESSAGES } from '../translations'; @@ -18,10 +23,6 @@ import { ResponseActionFileDownloadLink } from '../../response_action_file_downl import { ExecuteActionHostResponse } from '../../endpoint_execute_action'; import { getEmptyValue } from '../../../../common/components/empty_value'; -import type { - ResponseActionUploadOutputContent, - ResponseActionUploadParameters, -} from '../../../../../common/endpoint/types'; import { type ActionDetails, type MaybeImmutable } from '../../../../../common/endpoint/types'; const emptyValue = getEmptyValue(); @@ -80,12 +81,6 @@ const StyledEuiFlexGroup = euiStyled(EuiFlexGroup).attrs({ overflow-y: auto; `; -const isUploadAction = ( - action: MaybeImmutable -): action is ActionDetails => { - return action.command === 'upload'; -}; - const OutputContent = memo<{ action: MaybeImmutable; 'data-test-subj'?: string }>( ({ action, 'data-test-subj': dataTestSubj }) => { const getTestId = useTestIdGenerator(dataTestSubj); @@ -122,7 +117,7 @@ const OutputContent = memo<{ action: MaybeImmutable; 'data-test-s return <>{OUTPUT_MESSAGES.hasFailed(command)}; } - if (command === 'get-file') { + if (isGetFileAction(action)) { return ( <> {OUTPUT_MESSAGES.wasSuccessful(command)} @@ -136,7 +131,7 @@ const OutputContent = memo<{ action: MaybeImmutable; 'data-test-s ); } - if (command === 'execute') { + if (isExecuteAction(action)) { return ( {action.agents.map((agentId) => ( diff --git a/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_get_action_details.ts b/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_get_action_details.ts index cf017536762df..01c09da5d9be4 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_get_action_details.ts +++ b/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_get_action_details.ts @@ -14,22 +14,26 @@ import { ACTION_DETAILS_ROUTE } from '../../../../common/endpoint/constants'; import type { ActionDetailsApiResponse, EndpointActionDataParameterTypes, + EndpointActionResponseDataOutput, } from '../../../../common/endpoint/types'; export const useGetActionDetails = < - TOutputType extends object = object, + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput, TParameters extends EndpointActionDataParameterTypes = EndpointActionDataParameterTypes >( actionId: string, - options: UseQueryOptions, IHttpFetchError> = {} -): UseQueryResult, IHttpFetchError> => { + options: UseQueryOptions< + ActionDetailsApiResponse, + IHttpFetchError + > = {} +): UseQueryResult, IHttpFetchError> => { const http = useHttp(); - return useQuery, IHttpFetchError>({ + return useQuery, IHttpFetchError>({ queryKey: ['get-action-details', actionId], ...options, queryFn: () => { - return http.get>( + return http.get>( resolvePathVariables(ACTION_DETAILS_ROUTE, { action_id: actionId.trim() || 'undefined' }), { version: '2023-10-31', diff --git a/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_get_automated_action_list.ts b/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_get_automated_action_list.ts index dc6832ce04f46..03828cba319c2 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_get_automated_action_list.ts +++ b/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_get_automated_action_list.ts @@ -152,6 +152,7 @@ const combineResponse = ( return { id: action.EndpointActions.action_id, agents: action.agent.id as string[], + agentType: 'endpoint', parameters, ...(alertId?.length ? { alertIds: alertId } : {}), ...(rule diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/response_actions.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/response_actions.ts index 8a5c77c2a61b0..c909b6323ad26 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/response_actions.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/response_actions.ts @@ -23,6 +23,7 @@ import type { ResponseActionExecuteOutputContent, ResponseActionGetFileOutputContent, ResponseActionGetFileParameters, + EndpointActionResponseDataOutput, } from '../../../common/endpoint/types'; import { getFileDownloadId } from '../../../common/endpoint/service/response_actions/get_file_download_id'; import { @@ -79,18 +80,19 @@ export const sendEndpointActionResponse = async ( action: ActionDetails, { state }: { state?: 'success' | 'failure' } = {} ): Promise => { - const endpointResponse = endpointActionGenerator.generateResponse({ - agent: { id: action.agents[0] }, - EndpointActions: { - action_id: action.id, - data: { - command: action.command as EndpointActionData['command'], - comment: '', - ...getOutputDataIfNeeded(action), + const endpointResponse = + endpointActionGenerator.generateResponse({ + agent: { id: action.agents[0] }, + EndpointActions: { + action_id: action.id, + data: { + command: action.command as EndpointActionData['command'], + comment: '', + ...getOutputDataIfNeeded(action), + }, + started_at: action.startedAt, }, - started_at: action.startedAt, - }, - }); + }); // 20% of the time we generate an error if (state === 'failure' || (state !== 'success' && endpointActionGenerator.randomFloat() < 0.2)) { @@ -103,7 +105,8 @@ export const sendEndpointActionResponse = async ( endpointResponse.EndpointActions.data.output ) { ( - endpointResponse.EndpointActions.data.output.content as ResponseActionGetFileOutputContent + endpointResponse.EndpointActions.data.output + .content as unknown as ResponseActionGetFileOutputContent ).code = endpointActionGenerator.randomGetFileFailureCode(); } @@ -112,7 +115,8 @@ export const sendEndpointActionResponse = async ( endpointResponse.EndpointActions.data.output ) { ( - endpointResponse.EndpointActions.data.output.content as ResponseActionExecuteOutputContent + endpointResponse.EndpointActions.data.output + .content as unknown as ResponseActionExecuteOutputContent ).stderr = 'execute command timed out'; } } @@ -168,7 +172,7 @@ export const sendEndpointActionResponse = async ( ? '/execute/file/path' : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion ( - action as ActionDetails< + action as unknown as ActionDetails< ResponseActionGetFileOutputContent, ResponseActionGetFileParameters > @@ -244,12 +248,11 @@ export const sendEndpointActionResponse = async ( .then(() => sleep(2000)); } - return endpointResponse; + return endpointResponse as unknown as LogsEndpointActionResponse; }; -type ResponseOutput = Pick< - LogsEndpointActionResponse['EndpointActions']['data'], - 'output' ->; +type ResponseOutput< + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput +> = Pick['EndpointActions']['data'], 'output'>; const getOutputDataIfNeeded = (action: ActionDetails): ResponseOutput => { const commentUppercase = (action?.comment ?? '').toUpperCase(); @@ -262,7 +265,7 @@ const getOutputDataIfNeeded = (action: ActionDetails): ResponseOutput => { entries: endpointActionGenerator.randomResponseActionProcesses(100), }, }, - } as ResponseOutput; + } as unknown as ResponseOutput; case 'get-file': return { @@ -275,7 +278,7 @@ const getOutputDataIfNeeded = (action: ActionDetails): ResponseOutput => { { type: 'file', path: ( - action as ActionDetails< + action as unknown as ActionDetails< ResponseActionGetFileOutputContent, ResponseActionGetFileParameters > @@ -287,7 +290,7 @@ const getOutputDataIfNeeded = (action: ActionDetails): ResponseOutput => { ], }, }, - } as ResponseOutput; + } as unknown as ResponseOutput; case 'execute': const executeOutput: Partial = { @@ -309,7 +312,7 @@ const getOutputDataIfNeeded = (action: ActionDetails): ResponseOutput => { output: endpointActionGenerator.generateExecuteActionResponseOutput({ content: executeOutput, }), - } as ResponseOutput; + } as unknown as ResponseOutput; default: return { output: undefined }; diff --git a/x-pack/plugins/security_solution/server/endpoint/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/mocks.ts index 477d1e70be966..55e13b46c7167 100644 --- a/x-pack/plugins/security_solution/server/endpoint/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/mocks.ts @@ -102,6 +102,7 @@ export const createMockEndpointAppContextService = ( const fleetToHostFilesClientMock = createFleetToHostFilesClientMock(); const fleetActionsClientMock = createFleetActionsClientMock(); const loggerFactory = loggingSystemMock.create(); + const featureUsageMock = createFeatureUsageServiceMock(); return { start: jest.fn(), @@ -120,7 +121,7 @@ export const createMockEndpointAppContextService = ( getFleetToHostFilesClient: jest.fn(async () => fleetToHostFilesClientMock), setup: jest.fn(), getLicenseService: jest.fn(), - getFeatureUsageService: jest.fn(), + getFeatureUsageService: jest.fn().mockReturnValue(featureUsageMock), getExceptionListsClient: jest.fn(), getMessageSigningService: jest.fn(), getFleetActionsClient: jest.fn(async (_) => fleetActionsClientMock), diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.test.ts index 055ef330cb08f..74f222b64d2b9 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.test.ts @@ -73,6 +73,7 @@ import { omit, set } from 'lodash'; import type { ResponseActionAgentType } from '../../../../common/endpoint/service/response_actions/constants'; import { responseActionsClientMock } from '../../services/actions/clients/mocks'; import type { ActionsApiRequestHandlerContext } from '@kbn/actions-plugin/server'; +import { sentinelOneMock } from '../../services/actions/clients/sentinelone/mock'; jest.mock('../../services', () => { const realModule = jest.requireActual('../../services'); @@ -1184,7 +1185,7 @@ describe('Response actions', () => { }; httpHandlerContextMock.actions = Promise.resolve({ - getActionsClient: () => responseActionsClientMock.createConnectorActionsClient(), + getActionsClient: () => sentinelOneMock.createConnectorActionsClient(), } as unknown as jest.Mocked); // Set the esClient to be used in the handler context diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts index 4e8fdc997572a..0c573b561479f 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts @@ -7,7 +7,7 @@ import type { RequestHandler } from '@kbn/core/server'; import type { TypeOf } from '@kbn/config-schema'; -import { dump } from '../../utils/dump'; +import { stringify } from '../../utils/stringify'; import { getResponseActionsClient } from '../../services'; import type { ResponseActionsClient } from '../../services/actions/clients/lib/types'; import { CustomHttpRequestError } from '../../../utils/custom_http_request_error'; @@ -292,7 +292,7 @@ function responseActionRequestHandler { - logger.debug(`response action [${command}]:\n${dump(req.body)}`); + logger.debug(`response action [${command}]:\n${stringify(req.body)}`); // Note: because our API schemas are defined as module static variables (as opposed to a // `getter` function), we need to include this additional validation here, since diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/status.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/status.test.ts index 455ef9ec31946..d7b8824745cd0 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/status.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/status.test.ts @@ -36,6 +36,7 @@ import type { } from '../../../../common/endpoint/types'; import { EndpointActionGenerator } from '../../../../common/endpoint/data_generators/endpoint_action_generator'; import { ActionStatusRequestSchema } from '../../../../common/api/endpoint'; +import { AGENT_ACTIONS_RESULTS_INDEX } from '@kbn/fleet-plugin/common'; describe('Endpoint Pending Action Summary API', () => { let endpointAppContextService: EndpointAppContextService; @@ -109,6 +110,8 @@ describe('Endpoint Pending Action Summary API', () => { break; case ACTION_RESPONSE_INDICES.join(): + case AGENT_ACTIONS_RESULTS_INDEX: + case ENDPOINT_ACTION_RESPONSES_INDEX_PATTERN: items.push(...endpointResponses.splice(0, size)); index = ENDPOINT_ACTION_RESPONSES_INDEX_PATTERN; break; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/action_details_by_id.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_details_by_id.test.ts index 54d536e314edd..861a8c8870fa4 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/action_details_by_id.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_details_by_id.test.ts @@ -66,7 +66,9 @@ describe('When using `getActionDetailsById()', () => { await expect( getActionDetailsById(esClient, endpointAppContextService.getEndpointMetadataService(), '123') ).resolves.toEqual({ + action: '123', agents: ['agent-a'], + agentType: 'endpoint', hosts: { 'agent-a': { name: 'Host-agent-a' } }, command: 'kill-process', completedAt: '2022-04-30T16:08:47.449Z', diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/action_details_by_id.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_details_by_id.ts index 8e3d6ddad12b8..7863eb4507e64 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/action_details_by_id.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_details_by_id.ts @@ -7,30 +7,33 @@ import type { ElasticsearchClient } from '@kbn/core/server'; +import { fetchActionResponses } from './fetch_action_responses'; import { ENDPOINT_ACTIONS_INDEX } from '../../../../common/endpoint/constants'; import { formatEndpointActionResults, categorizeResponseResults, - getActionCompletionInfo, mapToNormalizedActionRequest, getAgentHostNamesWithIds, - getActionStatus, + createActionDetailsRecord, } from './utils'; import type { ActionDetails, ActivityLogActionResponse, - EndpointActionResponse, EndpointActivityLogAction, EndpointActivityLogActionResponse, LogsEndpointAction, - LogsEndpointActionResponse, } from '../../../../common/endpoint/types'; import { catchAndWrapError } from '../../utils'; import { EndpointError } from '../../../../common/endpoint/errors'; import { NotFoundError } from '../../errors'; -import { ACTION_RESPONSE_INDICES, ACTIONS_SEARCH_PAGE_SIZE } from './constants'; import type { EndpointMetadataService } from '../metadata'; +/** + * Get Action Details for a single action id + * @param esClient + * @param metadataService + * @param actionId + */ export const getActionDetailsById = async ( esClient: ElasticsearchClient, metadataService: EndpointMetadataService, @@ -43,7 +46,7 @@ export const getActionDetailsById = async ( @@ -63,23 +66,7 @@ export const getActionDetailsById = async ( - { - index: ACTION_RESPONSE_INDICES, - size: ACTIONS_SEARCH_PAGE_SIZE, - body: { - query: { - bool: { - filter: [{ term: { action_id: actionId } }], - }, - }, - }, - }, - { ignore: [404] } - ) - .catch(catchAndWrapError), + fetchActionResponses({ esClient, actionIds: [actionId] }).then((response) => response.data), ]); actionRequestsLogEntries = formatEndpointActionResults( @@ -95,8 +82,8 @@ export const getActionDetailsById = async ; + results: allResponseEsHits, + }); } catch (error) { throw new EndpointError(error.message, error); } @@ -113,36 +100,5 @@ export const getActionDetailsById = async ((acc, id) => { - acc[id] = { name: agentsHostInfo[id] ?? '' }; - return acc; - }, {}), - command: normalizedActionRequest.command, - startedAt: normalizedActionRequest.createdAt, - isCompleted, - completedAt, - wasSuccessful, - errors, - isExpired, - status, - outputs, - agentState, - createdBy: normalizedActionRequest.createdBy, - comment: normalizedActionRequest.comment, - parameters: normalizedActionRequest.parameters, - }; - - return actionDetails as T; + return createActionDetailsRecord(normalizedActionRequest, actionResponses, agentsHostInfo); }; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/action_list.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_list.test.ts index ebf88e6effd2e..70ccd7af8ecb5 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/action_list.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_list.test.ts @@ -89,7 +89,9 @@ describe('When using `getActionList()', () => { endDate: undefined, data: [ { + action: '123', agents: ['agent-a'], + agentType: 'endpoint', hosts: { 'agent-a': { name: 'Host-agent-a' } }, command: 'kill-process', completedAt: '2022-04-30T16:08:47.449Z', @@ -110,6 +112,24 @@ describe('When using `getActionList()', () => { wasSuccessful: true, }, }, + outputs: { + 'agent-a': { + content: { + code: 'ra_get-file_success_done', + contents: [ + { + file_name: 'bad_file.txt', + path: '/some/path/bad_file.txt', + sha256: '9558c5cb39622e9b3653203e772b129d6c634e7dbd7af1b244352fc1d704601f', + size: 1234, + type: 'file', + }, + ], + zip_size: 123, + }, + type: 'json', + }, + }, }, ], total: 1, @@ -152,7 +172,9 @@ describe('When using `getActionList()', () => { endDate: undefined, data: [ { + action: '123', agents: ['agent-a'], + agentType: 'endpoint', hosts: { 'agent-a': { name: 'Host-agent-a' } }, command: 'kill-process', completedAt: '2022-04-30T16:08:47.449Z', @@ -246,7 +268,9 @@ describe('When using `getActionList()', () => { statuses: undefined, data: [ { + action: '123', agents: ['agent-a', 'agent-b', 'agent-x'], + agentType: 'endpoint', hosts: { 'agent-a': { name: 'Host-agent-a' }, 'agent-b': { name: 'Host-agent-b' }, @@ -284,6 +308,7 @@ describe('When using `getActionList()', () => { errors: undefined, }, }, + outputs: {}, }, ], total: 1, @@ -319,16 +344,6 @@ describe('When using `getActionList()', () => { { bool: { filter: [ - { - term: { - input_type: 'endpoint', - }, - }, - { - term: { - type: 'INPUT_ACTION', - }, - }, { range: { '@timestamp': { @@ -415,16 +430,6 @@ describe('When using `getActionList()', () => { { bool: { filter: [ - { - term: { - input_type: 'endpoint', - }, - }, - { - term: { - type: 'INPUT_ACTION', - }, - }, { range: { '@timestamp': { diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/action_list.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_list.ts index f932eb7df23f9..f33c716da2434 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/action_list.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_list.ts @@ -7,20 +7,20 @@ import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import type { SearchTotalHits } from '@elastic/elasticsearch/lib/api/types'; +import { fetchActionResponses } from './fetch_action_responses'; import { ENDPOINT_DEFAULT_PAGE_SIZE } from '../../../../common/endpoint/constants'; import { CustomHttpRequestError } from '../../../utils/custom_http_request_error'; -import type { ActionDetails, ActionListApiResponse } from '../../../../common/endpoint/types'; +import type { ActionListApiResponse } from '../../../../common/endpoint/types'; import type { ResponseActionStatus } from '../../../../common/endpoint/service/response_actions/constants'; -import { getActions, getActionResponses } from '../../utils/action_list_helpers'; +import { getActions } from '../../utils/action_list_helpers'; import { formatEndpointActionResults, categorizeResponseResults, - getActionCompletionInfo, mapToNormalizedActionRequest, getAgentHostNamesWithIds, - getActionStatus, + createActionDetailsRecord, } from './utils'; import type { EndpointMetadataService } from '../metadata'; import { ACTIONS_SEARCH_PAGE_SIZE } from './constants'; @@ -237,11 +237,8 @@ const getActionDetailsList = async ({ // get all responses for given action Ids and agent Ids // and get host metadata info with queried agents [actionResponses, agentsHostInfo] = await Promise.all([ - getActionResponses({ - actionIds: actionReqIds, - elasticAgentIds, - esClient, - }), + fetchActionResponses({ esClient, agentIds: elasticAgentIds, actionIds: actionReqIds }), + await getAgentHostNamesWithIds({ esClient, metadataService, @@ -262,7 +259,7 @@ const getActionDetailsList = async ({ // categorize responses as fleet and endpoint responses const categorizedResponses = categorizeResponseResults({ - results: actionResponses?.body?.hits?.hits, + results: actionResponses.data, }); // compute action details list for each action id @@ -274,41 +271,11 @@ const getActionDetailsList = async ({ : categorizedResponse.item.data.action_id === action.id ); - // find the specific response's details using that set of matching responses - const { isCompleted, completedAt, wasSuccessful, errors, agentState, outputs } = - getActionCompletionInfo(action, matchedResponses); - - const { isExpired, status } = getActionStatus({ - expirationDate: action.expiration, - isCompleted, - wasSuccessful, - }); + const actionRecord = createActionDetailsRecord(action, matchedResponses, agentsHostInfo); - const actionRecord: ActionListApiResponse['data'][number] = { - id: action.id, - agents: action.agents, - hosts: action.agents.reduce((acc, id) => { - acc[id] = { name: agentsHostInfo[id] ?? '' }; - return acc; - }, {}), - command: action.command, - startedAt: action.createdAt, - isCompleted, - completedAt, - wasSuccessful, - errors: action.error?.message ? [action.error.message] : errors, - agentState, - isExpired, - status, - // 8.8 onwards, show outputs only for actions with matching requested action ids - outputs: withOutputs && withOutputs.includes(action.id) ? outputs : undefined, - createdBy: action.createdBy, - comment: action.comment, - parameters: action.parameters, - alertIds: action.alertIds, - ruleId: action.ruleId, - ruleName: action.ruleName, - }; + if (withOutputs && !withOutputs.includes(action.id)) { + delete actionRecord.outputs; + } return actionRecord; }); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/endpoint_actions_client.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/endpoint_actions_client.ts index a999659f2273a..2acc6dec8f2a2 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/endpoint_actions_client.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/endpoint_actions_client.ts @@ -5,9 +5,12 @@ * 2.0. */ -import { dump } from '../../../utils/dump'; +import { stringify } from '../../../utils/stringify'; import type { HapiReadableStream } from '../../../../types'; -import type { ResponseActionsApiCommandNames } from '../../../../../common/endpoint/service/response_actions/constants'; +import type { + ResponseActionsApiCommandNames, + ResponseActionAgentType, +} from '../../../../../common/endpoint/service/response_actions/constants'; import { updateCases } from '../create/update_cases'; import type { CreateActionPayload } from '../create/types'; import type { @@ -36,6 +39,8 @@ import type { } from '../../../../../common/endpoint/types'; export class EndpointActionsClient extends ResponseActionsClientImpl { + protected readonly agentType: ResponseActionAgentType = 'endpoint'; + private async checkAgentIds(ids: string[]): Promise<{ valid: string[]; invalid: string[]; @@ -83,7 +88,7 @@ export class EndpointActionsClient extends ResponseActionsClientImpl { }); } catch (err) { // failures during update of cases should not cause the response action to fail. Just log error - this.log.warn(`failed to update cases: ${err.message}\n${dump(err)}`); + this.log.warn(`failed to update cases: ${err.message}\n${stringify(err)}`); } return response as TResponse; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/errors.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/errors.ts index 300f2fa56cade..2e644f9a3a760 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/errors.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/errors.ts @@ -8,7 +8,7 @@ /* eslint-disable max-classes-per-file */ import type { ResponseActionsApiCommandNames } from '../../../../../common/endpoint/service/response_actions/constants'; -import { dump } from '../../../utils/dump'; +import { stringify } from '../../../utils/stringify'; import { CustomHttpRequestError } from '../../../../utils/custom_http_request_error'; /** @@ -25,7 +25,7 @@ export class ResponseActionsClientError extends CustomHttpRequestError { } toString() { - return JSON.stringify(dump(this.toJSON()), null, 2); + return JSON.stringify(stringify(this.toJSON()), null, 2); } } diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/get_response_actions_client.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/get_response_actions_client.test.ts index f0cee2a616462..224c8eac855ed 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/get_response_actions_client.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/get_response_actions_client.test.ts @@ -11,6 +11,7 @@ import { RESPONSE_ACTION_AGENT_TYPE } from '../../../../../common/endpoint/servi import { getResponseActionsClient } from '../..'; import { ResponseActionsClientImpl } from './lib/base_response_actions_client'; import { UnsupportedResponseActionsAgentTypeError } from './errors'; +import { sentinelOneMock } from './sentinelone/mock'; describe('getResponseActionsClient()', () => { let options: GetResponseActionsClientConstructorOptions; @@ -18,7 +19,7 @@ describe('getResponseActionsClient()', () => { beforeEach(() => { options = { ...responseActionsClientMock.createConstructorOptions(), - connectorActions: responseActionsClientMock.createConnectorActionsClient(), + connectorActions: sentinelOneMock.createConnectorActionsClient(), }; }); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.test.ts index 7b6d991e28f0b..aaceb2d6aef75 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +// eslint-disable-next-line max-classes-per-file import type { ResponseActionsClient } from './types'; import type { ResponseActionsClientUpdateCasesOptions, @@ -16,6 +17,7 @@ import type { ActionDetails, LogsEndpointAction, LogsEndpointActionResponse, + EndpointActionResponseDataOutput, } from '../../../../../../common/endpoint/types'; import type { EndpointAppContextService } from '../../../../endpoint_app_context_services'; import type { ElasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; @@ -30,6 +32,8 @@ import { ENDPOINT_ACTIONS_INDEX } from '../../../../../../common/endpoint/consta import type { DeepMutable } from '../../../../../../common/endpoint/types/utility_types'; import { set } from 'lodash'; import { responseActionsClientMock } from '../mocks'; +import type { ResponseActionAgentType } from '../../../../../../common/endpoint/service/response_actions/constants'; +import { getResponseActionFeatureKey } from '../../../feature_usage/feature_keys'; jest.mock('../../action_details_by_id', () => { const original = jest.requireActual('../../action_details_by_id'); @@ -43,6 +47,7 @@ jest.mock('../../action_details_by_id', () => { const getActionDetailsByIdMock = _getActionDetailsById as jest.Mock; describe('ResponseActionsClientImpl base class', () => { + let constructorOptions: ReturnType; let esClient: ElasticsearchClientMock; let endpointAppContextService: EndpointAppContextService; let baseClassMock: MockClassWithExposedProtectedMembers; @@ -50,7 +55,7 @@ describe('ResponseActionsClientImpl base class', () => { let logger: Logger; beforeEach(async () => { - const constructorOptions = responseActionsClientMock.createConstructorOptions(); + constructorOptions = responseActionsClientMock.createConstructorOptions(); esClient = constructorOptions.esClient; casesClient = constructorOptions.casesClient; @@ -361,14 +366,29 @@ describe('ResponseActionsClientImpl base class', () => { await expect( baseClassMock.writeActionRequestToEndpointIndex(indexDocOptions) ).resolves.toEqual(expectedIndexDoc); + + expect(endpointAppContextService.getFeatureUsageService().notifyUsage).toHaveBeenCalledWith( + getResponseActionFeatureKey(indexDocOptions.command) + ); + }); + + it('should notify feature usage', async () => { + await baseClassMock.writeActionRequestToEndpointIndex(indexDocOptions); + + expect(endpointAppContextService.getFeatureUsageService().notifyUsage).toHaveBeenCalledWith( + getResponseActionFeatureKey(indexDocOptions.command) + ); }); it('should set `EndpointActions.input_type` to the correct value', async () => { + const baseClassMock2 = new (class extends MockClassWithExposedProtectedMembers { + protected readonly agentType = 'sentinel_one'; + })(constructorOptions); indexDocOptions.agent_type = 'sentinel_one'; set(expectedIndexDoc, 'EndpointActions.input_type', 'sentinel_one'); await expect( - baseClassMock.writeActionRequestToEndpointIndex(indexDocOptions) + baseClassMock2.writeActionRequestToEndpointIndex(indexDocOptions) ).resolves.toEqual(expectedIndexDoc); }); @@ -457,12 +477,14 @@ describe('ResponseActionsClientImpl base class', () => { '@timestamp': expect.any(String), EndpointActions: { action_id: '1-2-3', + input_type: 'endpoint', completed_at: expect.any(String), + started_at: expect.any(String), data: { command: 'isolate', comment: 'some comment', + output: undefined, }, - started_at: expect.any(String), }, agent: { id: '123', @@ -470,7 +492,7 @@ describe('ResponseActionsClientImpl base class', () => { error: { message: 'test error', }, - }); + } as LogsEndpointActionResponse); }); it('should throw ResponseActionsClientError if operation fails', async () => { @@ -491,6 +513,8 @@ describe('ResponseActionsClientImpl base class', () => { }); class MockClassWithExposedProtectedMembers extends ResponseActionsClientImpl { + protected readonly agentType: ResponseActionAgentType = 'endpoint'; + public async updateCases(options: ResponseActionsClientUpdateCasesOptions): Promise { return super.updateCases(options); } @@ -507,7 +531,9 @@ class MockClassWithExposedProtectedMembers extends ResponseActionsClientImpl { return super.writeActionRequestToEndpointIndex(actionRequest); } - public async writeActionResponseToEndpointIndex( + public async writeActionResponseToEndpointIndex< + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput + >( options: ResponseActionsClientWriteActionResponseToEndpointIndexOptions ): Promise> { return super.writeActionResponseToEndpointIndex(options); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.ts index cea80bd3f9bcd..68e8db5fa1e69 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.ts @@ -13,7 +13,10 @@ import { AttachmentType } from '@kbn/cases-plugin/common'; import type { BulkCreateArgs } from '@kbn/cases-plugin/server/client/attachments/types'; import type { EndpointAppContextService } from '../../../../endpoint_app_context_services'; import { APP_ID } from '../../../../../../common'; -import type { ResponseActionsApiCommandNames } from '../../../../../../common/endpoint/service/response_actions/constants'; +import type { + ResponseActionsApiCommandNames, + ResponseActionAgentType, +} from '../../../../../../common/endpoint/service/response_actions/constants'; import { getActionDetailsById } from '../../action_details_by_id'; import { ResponseActionsClientError, ResponseActionsNotSupportedError } from '../errors'; import { @@ -42,6 +45,7 @@ import type { LogsEndpointAction, EndpointActionDataParameterTypes, LogsEndpointActionResponse, + EndpointActionResponseDataOutput, } from '../../../../../../common/endpoint/types'; import type { IsolationRouteRequestBody, @@ -52,7 +56,7 @@ import type { ResponseActionsRequestBody, } from '../../../../../../common/api/endpoint'; import type { CreateActionPayload } from '../../create/types'; -import { dump } from '../../../../utils/dump'; +import { stringify } from '../../../../utils/stringify'; export interface ResponseActionsClientOptions { endpointService: EndpointAppContextService; @@ -82,7 +86,7 @@ export type ResponseActionsClientWriteActionRequestToEndpointIndexOptions = Pick; export type ResponseActionsClientWriteActionResponseToEndpointIndexOptions< - TOutputContent extends object = object + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput > = { agentId: LogsEndpointActionResponse['agent']['id']; actionId: string; @@ -92,9 +96,11 @@ export type ResponseActionsClientWriteActionResponseToEndpointIndexOptions< /** * Base class for a Response Actions client */ -export class ResponseActionsClientImpl implements ResponseActionsClient { +export abstract class ResponseActionsClientImpl implements ResponseActionsClient { protected readonly log: Logger; + protected abstract readonly agentType: ResponseActionAgentType; + constructor(protected readonly options: ResponseActionsClientOptions) { this.log = options.endpointService.createLogger( this.constructor.name ?? 'ResponseActionsClient' @@ -158,7 +164,7 @@ export class ResponseActionsClientImpl implements ResponseActionsClient { return; } - this.log.debug(`Updating cases:\n${dump(allCases)}`); + this.log.debug(`Updating cases:\n${stringify(allCases)}`); // Create an attachment for each case that includes info. about the response actions taken against the hosts const attachments = allCases.map(() => ({ @@ -181,14 +187,14 @@ export class ResponseActionsClientImpl implements ResponseActionsClient { .catch((err) => { // Log any error, BUT: do not fail execution this.log.warn( - `Attempt to update case ID [${caseId}] failed: ${err.message}\n${dump(err)}` + `Attempt to update case ID [${caseId}] failed: ${err.message}\n${stringify(err)}` ); return null; }) ) ); - this.log.debug(`Update to cases done:\n${dump(casesUpdateResponse)}`); + this.log.debug(`Update to cases done:\n${stringify(casesUpdateResponse)}`); } /** @@ -213,6 +219,8 @@ export class ResponseActionsClientImpl implements ResponseActionsClient { protected async writeActionRequestToEndpointIndex( actionRequest: ResponseActionsClientWriteActionRequestToEndpointIndexOptions ): Promise { + this.notifyUsage(actionRequest.command); + const doc: LogsEndpointAction = { '@timestamp': new Date().toISOString(), agent: { @@ -222,7 +230,7 @@ export class ResponseActionsClientImpl implements ResponseActionsClient { action_id: uuidv4(), expiration: getActionRequestExpiration(), type: 'INPUT_ACTION', - input_type: actionRequest.agent_type ?? 'endpoint', + input_type: this.agentType, data: { command: actionRequest.command, comment: actionRequest.comment ?? undefined, @@ -274,7 +282,10 @@ export class ResponseActionsClientImpl implements ResponseActionsClient { * @param options * @protected */ - protected async writeActionResponseToEndpointIndex({ + protected async writeActionResponseToEndpointIndex< + // Default type purposely set to empty object in order to ensure proper types are used when calling the method + TOutputContent extends EndpointActionResponseDataOutput = Record + >({ actionId, error, agentId, @@ -290,6 +301,7 @@ export class ResponseActionsClientImpl implements ResponseActionsClient { }, EndpointActions: { action_id: actionId, + input_type: this.agentType, started_at: timestamp, completed_at: timestamp, data, @@ -297,10 +309,10 @@ export class ResponseActionsClientImpl implements ResponseActionsClient { error, }; - this.log.debug(`Writing response action response:\n${dump(doc)}`); + this.log.debug(`Writing response action response:\n${stringify(doc)}`); await this.options.esClient - .index({ + .index>({ index: ENDPOINT_ACTION_RESPONSES_INDEX, document: doc, refresh: 'wait_for', @@ -316,6 +328,20 @@ export class ResponseActionsClientImpl implements ResponseActionsClient { return doc; } + protected notifyUsage(responseAction: ResponseActionsApiCommandNames): void { + const usageService = this.options.endpointService.getFeatureUsageService(); + const featureKey = usageService.getResponseActionFeatureKey(responseAction); + + if (!featureKey) { + this.log.warn( + `Response action [${responseAction}] does not have a usage feature key defined!` + ); + return; + } + + usageService.notifyUsage(featureKey); + } + public async isolate(options: IsolationRouteRequestBody): Promise { throw new ResponseActionsNotSupportedError('isolate'); } diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/mocks.ts index 27773a898b932..2523765e5f450 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/mocks.ts @@ -5,10 +5,8 @@ * 2.0. */ -import type { ActionsClientMock } from '@kbn/actions-plugin/server/actions_client/actions_client.mock'; import { actionsClientMock } from '@kbn/actions-plugin/server/actions_client/actions_client.mock'; import type { ConnectorWithExtraFindData } from '@kbn/actions-plugin/server/application/connector/types'; -import { SENTINELONE_CONNECTOR_ID } from '@kbn/stack-connectors-plugin/common/sentinelone/constants'; import type { DeepPartial } from 'utility-types'; import type { ActionTypeExecutorResult } from '@kbn/actions-plugin/common'; import type { ElasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; @@ -138,29 +136,6 @@ const createIsolateOptionsMock = ( return merge(isolateOptions, overrides); }; -const createConnectorActionsClientMock = (): ActionsClientMock => { - const client = actionsClientMock.create(); - - // Mock result of retrieving list of connectors - (client.getAll as jest.Mock).mockImplementation(async () => { - const result: ConnectorWithExtraFindData[] = [ - // SentinelOne connector - createConnectorMock({ - actionTypeId: SENTINELONE_CONNECTOR_ID, - id: 's1-connector-instance-id', - }), - ]; - - return result; - }); - - (client.execute as jest.Mock).mockImplementation(async () => { - return createConnectorAcitonExecuteResponseMock(); - }); - - return client; -}; - const createConnectorMock = ( overrides: DeepPartial = {} ): ConnectorWithExtraFindData => { @@ -180,10 +155,10 @@ const createConnectorMock = ( ); }; -const createConnectorAcitonExecuteResponseMock = ( - overrides: DeepPartial> = {} +const createConnectorActionExecuteResponseMock = ( + overrides: DeepPartial> = {} ): ActionTypeExecutorResult<{}> => { - const result: ActionTypeExecutorResult<{}> = { + const result: ActionTypeExecutorResult = { actionId: 'execute-response-mock-1', data: undefined, message: 'some mock message', @@ -199,11 +174,13 @@ export const responseActionsClientMock = Object.freeze({ createConstructorOptions: createConstructorOptionsMock, createIsolateOptions: createIsolateOptionsMock, createReleaseOptions: createIsolateOptionsMock, + // TODO:PT add more methods to get option mocks for other class methods createIndexedResponse: createEsIndexTransportResponseMock, - createConnectorActionsClient: createConnectorActionsClientMock, + // Some common mocks when working with connector actions + createConnectorActionsClient: actionsClientMock.create, createConnector: createConnectorMock, - createConnectorActionExecuteResponse: createConnectorAcitonExecuteResponseMock, + createConnectorActionExecuteResponse: createConnectorActionExecuteResponseMock, }); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/mock.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/mock.ts new file mode 100644 index 0000000000000..48a6ace18adc5 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/mock.ts @@ -0,0 +1,177 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { SentinelOneGetAgentsResponse } from '@kbn/stack-connectors-plugin/common/sentinelone/types'; +import { + SENTINELONE_CONNECTOR_ID, + SUB_ACTION, +} from '@kbn/stack-connectors-plugin/common/sentinelone/constants'; +import type { ActionsClientMock } from '@kbn/actions-plugin/server/actions_client/actions_client.mock'; +import type { ConnectorWithExtraFindData } from '@kbn/actions-plugin/server/application/connector/types'; +import type { ResponseActionsClientOptionsMock } from '../mocks'; +import { responseActionsClientMock } from '../mocks'; + +export interface SentinelOneActionsClientOptionsMock extends ResponseActionsClientOptionsMock { + connectorActions: ActionsClientMock; +} + +const createSentinelOneGetAgentsApiResponseMock = (): SentinelOneGetAgentsResponse => { + return { + pagination: { + nextCursor: 'next-0', + totalItems: 1, + }, + errors: null, + data: [ + { + accountId: '11111111111', + accountName: 'Elastic', + groupUpdatedAt: null, + policyUpdatedAt: null, + activeDirectory: { + computerDistinguishedName: null, + computerMemberOf: [], + lastUserDistinguishedName: null, + lastUserMemberOf: [], + userPrincipalName: null, + mail: null, + }, + activeThreats: 0, + agentVersion: '23.3.2.12', + allowRemoteShell: true, + appsVulnerabilityStatus: 'not_applicable', + cloudProviders: {}, + computerName: 'sentinelone-1460', + consoleMigrationStatus: 'N/A', + coreCount: 1, + cpuCount: 1, + cpuId: 'ARM Cortex-A72', + createdAt: '2023-12-21T20:32:52.290978Z', + detectionState: null, + domain: 'unknown', + encryptedApplications: false, + externalId: '', + externalIp: '108.77.84.191', + firewallEnabled: true, + firstFullModeTime: null, + fullDiskScanLastUpdatedAt: '2023-12-21T20:57:55.690655Z', + groupId: '9999999999999', + groupIp: '108.77.84.x', + groupName: 'Default Group', + id: '1845174760470303882', + inRemoteShellSession: false, + infected: false, + installerType: '.deb', + isActive: true, + isDecommissioned: false, + isPendingUninstall: false, + isUninstalled: false, + isUpToDate: true, + lastActiveDate: '2023-12-26T21:34:28.032981Z', + lastIpToMgmt: '192.168.64.2', + lastLoggedInUserName: '', + licenseKey: '', + locationEnabled: false, + locationType: 'not_supported', + locations: null, + machineType: 'server', + mitigationMode: 'detect', + mitigationModeSuspicious: 'detect', + modelName: 'QEMU QEMU Virtual Machine', + networkInterfaces: [ + { + gatewayIp: '192.168.64.1', + gatewayMacAddress: 'be:d0:74:50:d8:64', + id: '1845174760470303883', + inet: ['192.168.64.2'], + inet6: ['fdf4:f033:b1d4:8c51:5054:ff:febc:6253'], + name: 'enp0s1', + physical: '52:54:00:BC:62:53', + }, + ], + networkQuarantineEnabled: false, + networkStatus: 'connecting', + operationalState: 'na', + operationalStateExpiration: null, + osArch: '64 bit', + osName: 'Linux', + osRevision: 'Ubuntu 22.04.3 LTS 5.15.0-91-generic', + osStartTime: '2023-12-21T20:31:51Z', + osType: 'linux', + osUsername: 'root', + rangerStatus: 'Enabled', + rangerVersion: '23.4.0.9', + registeredAt: '2023-12-21T20:32:52.286752Z', + remoteProfilingState: 'disabled', + remoteProfilingStateExpiration: null, + scanAbortedAt: null, + scanFinishedAt: '2023-12-21T20:57:55.690655Z', + scanStartedAt: '2023-12-21T20:33:31.170460Z', + scanStatus: 'finished', + serialNumber: null, + showAlertIcon: false, + siteId: '88888888888', + siteName: 'Default site', + storageName: null, + storageType: null, + tags: { sentinelone: [] }, + threatRebootRequired: false, + totalMemory: 1966, + updatedAt: '2023-12-26T21:35:35.986596Z', + userActionsNeeded: [], + uuid: 'a2f4603d-c9e2-d7a2-bec2-0d646f3bbc9f', + }, + ], + }; +}; + +const createConnectorActionsClientMock = (): ActionsClientMock => { + const client = responseActionsClientMock.createConnectorActionsClient(); + + (client.getAll as jest.Mock).mockImplementation(async () => { + const result: ConnectorWithExtraFindData[] = [ + // SentinelOne connector + responseActionsClientMock.createConnector({ + actionTypeId: SENTINELONE_CONNECTOR_ID, + id: 's1-connector-instance-id', + }), + ]; + + return result; + }); + + (client.execute as jest.Mock).mockImplementation( + async (options: Parameters[0]) => { + const subAction = options.params.subAction; + + switch (subAction) { + case SUB_ACTION.GET_AGENTS: + return responseActionsClientMock.createConnectorActionExecuteResponse({ + data: createSentinelOneGetAgentsApiResponseMock(), + }); + + default: + return responseActionsClientMock.createConnectorActionExecuteResponse(); + } + } + ); + + return client; +}; + +const createConstructorOptionsMock = (): SentinelOneActionsClientOptionsMock => { + return { + ...responseActionsClientMock.createConstructorOptions(), + connectorActions: createConnectorActionsClientMock(), + }; +}; + +export const sentinelOneMock = { + createGetAgentsResponse: createSentinelOneGetAgentsApiResponseMock, + createConnectorActionsClient: createConnectorActionsClientMock, + createConstructorOptions: createConstructorOptionsMock, +}; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.test.ts index a56b54ce2e65f..c506e8615ed04 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.test.ts @@ -7,11 +7,16 @@ import type { ResponseActionsClient } from '../lib/types'; import { responseActionsClientMock } from '../mocks'; -import type { SentinelOneActionsClientOptions } from '../../..'; -import { SentinelOneActionsClient } from '../../..'; +import { SentinelOneActionsClient } from './sentinel_one_actions_client'; import { getActionDetailsById as _getActionDetailsById } from '../../action_details_by_id'; import { ResponseActionsClientError, ResponseActionsNotSupportedError } from '../errors'; import type { ActionsClientMock } from '@kbn/actions-plugin/server/actions_client/actions_client.mock'; +import type { SentinelOneActionsClientOptionsMock } from './mock'; +import { sentinelOneMock } from './mock'; +import { + ENDPOINT_ACTION_RESPONSES_INDEX, + ENDPOINT_ACTIONS_INDEX, +} from '../../../../../../common/endpoint/constants'; jest.mock('../../action_details_by_id', () => { const originalMod = jest.requireActual('../../action_details_by_id'); @@ -25,27 +30,20 @@ jest.mock('../../action_details_by_id', () => { const getActionDetailsByIdMock = _getActionDetailsById as jest.Mock; describe('SentinelOneActionsClient class', () => { - let classConstructorOptions: SentinelOneActionsClientOptions; + let classConstructorOptions: SentinelOneActionsClientOptionsMock; let s1ActionsClient: ResponseActionsClient; let connectorActionsMock: ActionsClientMock; - const createS1IsolateOptions = () => + const createS1IsolationOptions = () => responseActionsClientMock.createIsolateOptions({ agent_type: 'sentinel_one' }); beforeEach(() => { - connectorActionsMock = responseActionsClientMock.createConnectorActionsClient(); - - connectorActionsMock.getAll(); - - classConstructorOptions = { - ...responseActionsClientMock.createConstructorOptions(), - connectorActions: connectorActionsMock, - }; + classConstructorOptions = sentinelOneMock.createConstructorOptions(); + connectorActionsMock = classConstructorOptions.connectorActions; s1ActionsClient = new SentinelOneActionsClient(classConstructorOptions); }); it.each([ - 'release', 'killProcess', 'suspendProcess', 'runningProcesses', @@ -66,7 +64,7 @@ describe('SentinelOneActionsClient class', () => { connectorActionsMock.getAll.mockImplementation(async () => { throw new Error('oh oh'); }); - const responsePromise = s1ActionsClient.isolate(createS1IsolateOptions()); + const responsePromise = s1ActionsClient.isolate(createS1IsolationOptions()); await expect(responsePromise).rejects.toBeInstanceOf(ResponseActionsClientError); await expect(responsePromise).rejects.toHaveProperty( @@ -81,7 +79,7 @@ describe('SentinelOneActionsClient class', () => { throw new Error('oh oh'); }); - await expect(s1ActionsClient.isolate(createS1IsolateOptions())).rejects.toMatchObject({ + await expect(s1ActionsClient.isolate(createS1IsolationOptions())).rejects.toMatchObject({ message: `Unable to retrieve list of stack connectors: oh oh`, statusCode: 400, }); @@ -100,14 +98,14 @@ describe('SentinelOneActionsClient class', () => { ])('should error if: %s', async (_, getAllImplementation) => { (connectorActionsMock.getAll as jest.Mock).mockImplementation(getAllImplementation); - await expect(s1ActionsClient.isolate(createS1IsolateOptions())).rejects.toMatchObject({ + await expect(s1ActionsClient.isolate(createS1IsolationOptions())).rejects.toMatchObject({ message: `No SentinelOne stack connector found`, statusCode: 400, }); }); it('should error if multiple agent ids are received', async () => { - const payload = createS1IsolateOptions(); + const payload = createS1IsolationOptions(); payload.endpoint_ids.push('second-host-id'); await expect(s1ActionsClient.isolate(payload)).rejects.toMatchObject({ @@ -118,7 +116,7 @@ describe('SentinelOneActionsClient class', () => { describe(`#isolate()`, () => { it('should send action to sentinelone', async () => { - await s1ActionsClient.isolate(createS1IsolateOptions()); + await s1ActionsClient.isolate(createS1IsolationOptions()); expect(connectorActionsMock.execute as jest.Mock).toHaveBeenCalledWith({ actionId: 's1-connector-instance-id', @@ -132,10 +130,82 @@ describe('SentinelOneActionsClient class', () => { }); it('should write action request and response to endpoint indexes', async () => { - await s1ActionsClient.isolate(createS1IsolateOptions()); + await s1ActionsClient.isolate(createS1IsolationOptions()); + + expect(classConstructorOptions.esClient.index).toHaveBeenCalledTimes(2); + expect(classConstructorOptions.esClient.index).toHaveBeenNthCalledWith( + 1, + { + document: { + '@timestamp': expect.any(String), + EndpointActions: { + action_id: expect.any(String), + data: { + command: 'isolate', + comment: 'test comment', + parameters: undefined, + hosts: { + '1-2-3': { + name: 'sentinelone-1460', + }, + }, + }, + expiration: expect.any(String), + input_type: 'sentinel_one', + type: 'INPUT_ACTION', + }, + agent: { id: ['1-2-3'] }, + user: { id: 'foo' }, + }, + index: ENDPOINT_ACTIONS_INDEX, + refresh: 'wait_for', + }, + { meta: true } + ); + expect(classConstructorOptions.esClient.index).toHaveBeenNthCalledWith(2, { + document: { + '@timestamp': expect.any(String), + EndpointActions: { + action_id: expect.any(String), + data: { command: 'isolate' }, + input_type: 'sentinel_one', + started_at: expect.any(String), + completed_at: expect.any(String), + }, + agent: { id: ['1-2-3'] }, + error: undefined, + }, + index: ENDPOINT_ACTION_RESPONSES_INDEX, + refresh: 'wait_for', + }); + }); + + it('should return action details', async () => { + await s1ActionsClient.isolate(createS1IsolationOptions()); + + expect(getActionDetailsByIdMock).toHaveBeenCalled(); + }); + }); + + describe('#release()', () => { + it('should send action to sentinelone', async () => { + await s1ActionsClient.release(createS1IsolationOptions()); + + expect(connectorActionsMock.execute as jest.Mock).toHaveBeenCalledWith({ + actionId: 's1-connector-instance-id', + params: { + subAction: 'releaseHost', + subActionParams: { + uuid: '1-2-3', + }, + }, + }); + }); + + it('should write action request and response to endpoint indexes', async () => { + await s1ActionsClient.release(createS1IsolationOptions()); - expect(classConstructorOptions.esClient.index).toHaveBeenCalledTimes(1); - // FIXME:PT once we start writing the Response, check above should be removed and new assertion added for it + expect(classConstructorOptions.esClient.index).toHaveBeenCalledTimes(2); expect(classConstructorOptions.esClient.index).toHaveBeenNthCalledWith( 1, { @@ -143,7 +213,16 @@ describe('SentinelOneActionsClient class', () => { '@timestamp': expect.any(String), EndpointActions: { action_id: expect.any(String), - data: { command: 'isolate', comment: 'test comment', parameters: undefined }, + data: { + command: 'unisolate', + comment: 'test comment', + parameters: undefined, + hosts: { + '1-2-3': { + name: 'sentinelone-1460', + }, + }, + }, expiration: expect.any(String), input_type: 'sentinel_one', type: 'INPUT_ACTION', @@ -151,15 +230,31 @@ describe('SentinelOneActionsClient class', () => { agent: { id: ['1-2-3'] }, user: { id: 'foo' }, }, - index: '.logs-endpoint.actions-default', + index: ENDPOINT_ACTIONS_INDEX, refresh: 'wait_for', }, { meta: true } ); + expect(classConstructorOptions.esClient.index).toHaveBeenNthCalledWith(2, { + document: { + '@timestamp': expect.any(String), + EndpointActions: { + action_id: expect.any(String), + data: { command: 'unisolate' }, + input_type: 'sentinel_one', + started_at: expect.any(String), + completed_at: expect.any(String), + }, + agent: { id: ['1-2-3'] }, + error: undefined, + }, + index: ENDPOINT_ACTION_RESPONSES_INDEX, + refresh: 'wait_for', + }); }); it('should return action details', async () => { - await s1ActionsClient.isolate(createS1IsolateOptions()); + await s1ActionsClient.release(createS1IsolationOptions()); expect(getActionDetailsByIdMock).toHaveBeenCalled(); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.ts index 4837f427a926b..d196232e83916 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.ts @@ -13,14 +13,23 @@ import { import type { ConnectorWithExtraFindData } from '@kbn/actions-plugin/server/application/connector/types'; import { once } from 'lodash'; import type { ActionTypeExecutorResult } from '@kbn/actions-plugin/common'; -import { dump } from '../../../../utils/dump'; +import type { + SentinelOneGetAgentsResponse, + SentinelOneGetAgentsParams, +} from '@kbn/stack-connectors-plugin/common/sentinelone/types'; +import type { ResponseActionAgentType } from '../../../../../../common/endpoint/service/response_actions/constants'; +import type { SentinelOneConnectorExecuteOptions } from './types'; +import { stringify } from '../../../../utils/stringify'; import { ResponseActionsClientError } from '../errors'; -import type { ActionDetails } from '../../../../../../common/endpoint/types'; +import type { ActionDetails, LogsEndpointAction } from '../../../../../../common/endpoint/types'; import type { IsolationRouteRequestBody, BaseActionRequestBody, } from '../../../../../../common/api/endpoint'; -import type { ResponseActionsClientOptions } from '../lib/base_response_actions_client'; +import type { + ResponseActionsClientOptions, + ResponseActionsClientWriteActionRequestToEndpointIndexOptions, +} from '../lib/base_response_actions_client'; import { ResponseActionsClientImpl } from '../lib/base_response_actions_client'; export type SentinelOneActionsClientOptions = ResponseActionsClientOptions & { @@ -28,6 +37,7 @@ export type SentinelOneActionsClientOptions = ResponseActionsClientOptions & { }; export class SentinelOneActionsClient extends ResponseActionsClientImpl { + protected readonly agentType: ResponseActionAgentType = 'sentinel_one'; private readonly connectorActionsClient: ActionsClient; private readonly getConnector: () => Promise; @@ -67,14 +77,27 @@ export class SentinelOneActionsClient extends ResponseActionsClientImpl { }); } + protected async writeActionRequestToEndpointIndex( + actionRequest: Omit + ): Promise { + const agentId = actionRequest.endpoint_ids[0]; + const agentDetails = await this.getAgentDetails(agentId); + + return super.writeActionRequestToEndpointIndex({ + ...actionRequest, + hosts: { + [agentId]: { name: agentDetails.computerName }, + }, + }); + } + /** - * Sends actions to SentinelOne directly + * Sends actions to SentinelOne directly (via Connector) * @private */ private async sendAction( actionType: SUB_ACTION, actionParams: object - // FIXME:PT type properly the options above once PR 168441 for 8.12 merges ): Promise> { const { id: connectorId } = await this.getConnector(); const executeOptions: Parameters[0] = { @@ -86,13 +109,13 @@ export class SentinelOneActionsClient extends ResponseActionsClientImpl { }; this.log.debug( - `calling connector actions 'execute()' for SentinelOne with:\n${dump(executeOptions)}` + `calling connector actions 'execute()' for SentinelOne with:\n${stringify(executeOptions)}` ); const actionSendResponse = await this.connectorActionsClient.execute(executeOptions); if (actionSendResponse.status === 'error') { - this.log.error(dump(actionSendResponse)); + this.log.error(stringify(actionSendResponse)); throw new ResponseActionsClientError( `Attempt to send [${actionType}] to SentinelOne failed: ${ @@ -103,12 +126,50 @@ export class SentinelOneActionsClient extends ResponseActionsClientImpl { ); } - this.log.debug(`Response:\n${dump(actionSendResponse)}`); + this.log.debug(`Response:\n${stringify(actionSendResponse)}`); return actionSendResponse; } + private async getAgentDetails(id: string): Promise { + const { id: connectorId } = await this.getConnector(); + const executeOptions: SentinelOneConnectorExecuteOptions = { + actionId: connectorId, + params: { + subAction: SUB_ACTION.GET_AGENTS, + subActionParams: { + uuid: id, + }, + }, + }; + + let s1ApiResponse: SentinelOneGetAgentsResponse | undefined; + + try { + const response = (await this.connectorActionsClient.execute( + executeOptions + )) as ActionTypeExecutorResult; + + this.log.debug(`Response for SentinelOne agent id [${id}] returned:\n${stringify(response)}`); + + s1ApiResponse = response.data; + } catch (err) { + throw new ResponseActionsClientError( + `Error while attempting to retrieve SentinelOne host with agent id [${id}]`, + 500, + err + ); + } + + if (!s1ApiResponse || !s1ApiResponse.data[0]) { + throw new ResponseActionsClientError(`SentinelOne agent id [${id}] not found`, 404); + } + + return s1ApiResponse.data[0]; + } + private async validateRequest(payload: BaseActionRequestBody): Promise { + // TODO:PT support multiple agents if (payload.endpoint_ids.length > 1) { throw new ResponseActionsClientError( `[body.endpoint_ids]: Multiple agents IDs not currently supported for SentinelOne`, @@ -118,30 +179,43 @@ export class SentinelOneActionsClient extends ResponseActionsClientImpl { } async isolate(options: IsolationRouteRequestBody): Promise { - // TODO:PT support multiple agents await this.validateRequest(options); + await this.sendAction(SUB_ACTION.ISOLATE_HOST, { uuid: options.endpoint_ids[0] }); - const agentUUID = options.endpoint_ids[0]; - - await this.sendAction(SUB_ACTION.ISOLATE_HOST, { - uuid: agentUUID, + const reqIndexOptions: ResponseActionsClientWriteActionRequestToEndpointIndexOptions = { + ...options, + command: 'isolate', + }; + const actionRequestDoc = await this.writeActionRequestToEndpointIndex(reqIndexOptions); + await this.writeActionResponseToEndpointIndex({ + actionId: actionRequestDoc.EndpointActions.action_id, + agentId: actionRequestDoc.agent.id, + data: { + command: actionRequestDoc.EndpointActions.data.command, + }, }); - // FIXME:PT need to grab data from the response above and store it with the Request or Response documents on our side + return this.fetchActionDetails(actionRequestDoc.EndpointActions.action_id); + } + + async release(options: IsolationRouteRequestBody): Promise { + await this.validateRequest(options); + await this.sendAction(SUB_ACTION.RELEASE_HOST, { + uuid: options.endpoint_ids[0], + }); const actionRequestDoc = await this.writeActionRequestToEndpointIndex({ ...options, - command: 'isolate', + command: 'unisolate', }); - // TODO: un-comment code below once we have proper authz given to `kibana_system` account (security issue #8190) - // await this.writeActionResponseToEndpointIndex({ - // actionId: actionRequestDoc.EndpointActions.action_id, - // agentId: actionRequestDoc.agent.id, - // data: { - // command: actionRequestDoc.EndpointActions.data.command, - // }, - // }); + await this.writeActionResponseToEndpointIndex({ + actionId: actionRequestDoc.EndpointActions.action_id, + agentId: actionRequestDoc.agent.id, + data: { + command: actionRequestDoc.EndpointActions.data.command, + }, + }); return this.fetchActionDetails(actionRequestDoc.EndpointActions.action_id); } diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/types.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/types.ts new file mode 100644 index 0000000000000..fbb28df5e4449 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/types.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. + */ + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import type { ActionsClient } from '@kbn/actions-plugin/server'; +import type { SUB_ACTION } from '@kbn/stack-connectors-plugin/common/sentinelone/constants'; + +type ConnectorActionsExecuteOptions = Parameters[0]; + +interface SentinelOneConnectorExecuteParams< + P extends Record = Record +> { + subAction: SUB_ACTION; + subActionParams: P; +} + +export type SentinelOneConnectorExecuteOptions< + P extends Record = Record +> = Omit & { + params: SentinelOneConnectorExecuteParams

    & Record; +}; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/create/index.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/create/index.ts index 1c3d57dc241b2..94cd181edc5e0 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/create/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/create/index.ts @@ -13,23 +13,13 @@ import type { ActionDetails, EndpointActionDataParameterTypes, HostMetadata, + EndpointActionResponseDataOutput, } from '../../../../../common/endpoint/types'; import type { EndpointAppContext } from '../../../types'; -import type { FeatureKeys } from '../../feature_usage'; import { getActionDetailsById } from '..'; import type { ActionCreateService, CreateActionMetadata, CreateActionPayload } from './types'; import { writeActionToIndices } from './write_action_to_indices'; -const commandToFeatureKeyMap = new Map([ - ['isolate', 'HOST_ISOLATION'], - ['unisolate', 'HOST_ISOLATION'], - ['kill-process', 'KILL_PROCESS'], - ['suspend-process', 'SUSPEND_PROCESS'], - ['running-processes', 'RUNNING_PROCESSES'], - ['get-file', 'GET_FILE'], - ['execute', 'EXECUTE'], -]); - const returnActionIdCommands: ResponseActionsApiCommandNames[] = ['isolate', 'unisolate']; export const actionCreateService = ( @@ -37,16 +27,18 @@ export const actionCreateService = ( endpointContext: EndpointAppContext ): ActionCreateService => { const createAction = async < - TOutputContent extends object = object, + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput, TParameters extends EndpointActionDataParameterTypes = EndpointActionDataParameterTypes >( payload: CreateActionPayload, agents: string[], { minimumLicenseRequired = 'basic' }: CreateActionMetadata = {} ): Promise> => { - const featureKey = commandToFeatureKeyMap.get(payload.command) as FeatureKeys; + const usageService = endpointContext.service.getFeatureUsageService(); + const featureKey = usageService.getResponseActionFeatureKey(payload.command); + if (featureKey) { - endpointContext.service.getFeatureUsageService().notifyUsage(featureKey); + usageService.notifyUsage(featureKey); } // create an Action ID and use that to dispatch action to ES & Fleet Server diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/create/types.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/create/types.ts index f8a10b18d594d..131869e5248fa 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/create/types.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/create/types.ts @@ -11,6 +11,7 @@ import type { ResponseActionBodySchema } from '../../../../../common/api/endpoin import type { ActionDetails, EndpointActionDataParameterTypes, + EndpointActionResponseDataOutput, } from '../../../../../common/endpoint/types'; import type { ResponseActionsApiCommandNames } from '../../../../../common/endpoint/service/response_actions/constants'; @@ -30,7 +31,7 @@ export interface CreateActionMetadata { export interface ActionCreateService { createActionFromAlert: (payload: CreateActionPayload, agents: string[]) => Promise; createAction: < - TOutputContent extends object = object, + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput, TParameters extends EndpointActionDataParameterTypes = EndpointActionDataParameterTypes >( payload: CreateActionPayload, diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/create/write_action_to_indices.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/create/write_action_to_indices.ts index b502ec082c69b..a0626b2e4d883 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/create/write_action_to_indices.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/create/write_action_to_indices.ts @@ -10,6 +10,7 @@ import type { Logger } from '@kbn/core/server'; import moment from 'moment'; import type { LicenseType } from '@kbn/licensing-plugin/common/types'; import type { FleetActionRequest } from '@kbn/fleet-plugin/server/services/actions/types'; +import { isExecuteAction } from '../../../../../common/endpoint/service/response_actions/type_guards'; import { DEFAULT_EXECUTE_ACTION_TIMEOUT } from '../../../../../common/endpoint/service/response_actions/constants'; import { ENDPOINT_ACTIONS_DS, @@ -143,6 +144,7 @@ export const writeActionToIndices = async ({ completed_at: moment().toISOString(), started_at: moment().toISOString(), data: doc.EndpointActions.data, + input_type: 'endpoint', }, }, logger, @@ -193,8 +195,8 @@ export const getActionParameters = ( action: Pick ): ResponseActionsExecuteParameters | Readonly<{}> | undefined => { // set timeout to 4h (if not specified or when timeout is specified as 0) when command is `execute` - if (action.command === 'execute') { - const actionRequestParams = action.parameters as ResponseActionsExecuteParameters; + if (isExecuteAction(action)) { + const actionRequestParams = action.parameters; if (typeof actionRequestParams?.timeout === 'undefined') { return { ...actionRequestParams, timeout: DEFAULT_EXECUTE_ACTION_TIMEOUT }; } diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/fetch_action_responses.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/fetch_action_responses.test.ts new file mode 100644 index 0000000000000..012379758fabd --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/fetch_action_responses.test.ts @@ -0,0 +1,232 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { applyActionListEsSearchMock } from './mocks'; +import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; +import type { ElasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; +import { fetchActionResponses } from './fetch_action_responses'; +import { BaseDataGenerator } from '../../../../common/endpoint/data_generators/base_data_generator'; +import { AGENT_ACTIONS_RESULTS_INDEX } from '@kbn/fleet-plugin/common'; +import { ENDPOINT_ACTION_RESPONSES_INDEX_PATTERN } from '../../../../common/endpoint/constants'; +import { ACTIONS_SEARCH_PAGE_SIZE } from './constants'; + +describe('fetchActionResponses()', () => { + let esClientMock: ElasticsearchClientMock; + + beforeEach(() => { + esClientMock = elasticsearchServiceMock.createScopedClusterClient().asInternalUser; + applyActionListEsSearchMock(esClientMock); + }); + + it('should return results', async () => { + await expect(fetchActionResponses({ esClient: esClientMock })).resolves.toEqual({ + data: [ + { + _id: 'ef278144-d8b9-45c6-9c3c-484c86b57d0b', + _index: '.fleet-actions-results', + _score: 1, + _source: { + '@timestamp': '2022-04-30T16:08:47.449Z', + action_data: { + command: 'get-file', + comment: '', + }, + action_id: '123', + agent_id: 'agent-a', + completed_at: '2022-04-30T10:53:59.449Z', + error: '', + started_at: '2022-04-30T12:56:00.449Z', + }, + }, + { + _id: 'ef278144-d8b9-45c6-9c3c-484c86b57d0b', + _index: '.ds-.logs-endpoint.action.responses-some_namespace-something', + _score: 1, + _source: { + '@timestamp': '2022-04-30T16:08:47.449Z', + EndpointActions: { + action_id: '123', + completed_at: '2022-04-30T10:53:59.449Z', + data: { + command: 'get-file', + comment: '', + output: { + content: { + code: 'ra_get-file_success_done', + contents: [ + { + file_name: 'bad_file.txt', + path: '/some/path/bad_file.txt', + sha256: '9558c5cb39622e9b3653203e772b129d6c634e7dbd7af1b244352fc1d704601f', + size: 1234, + type: 'file', + }, + ], + zip_size: 123, + }, + type: 'json', + }, + }, + started_at: '2022-04-30T12:56:00.449Z', + }, + agent: { + id: 'agent-a', + }, + }, + }, + { + _id: 'ef278144-d8b9-45c6-9c3c-484c86b57d0b', + _index: '.fleet-actions-results', + _score: 1, + _source: { + '@timestamp': '2022-04-30T16:08:47.449Z', + action_data: { + command: 'get-file', + comment: '', + }, + action_id: '123', + agent_id: 'agent-a', + completed_at: '2022-04-30T10:53:59.449Z', + error: '', + started_at: '2022-04-30T12:56:00.449Z', + }, + }, + { + _id: 'ef278144-d8b9-45c6-9c3c-484c86b57d0b', + _index: '.ds-.logs-endpoint.action.responses-some_namespace-something', + _score: 1, + _source: { + '@timestamp': '2022-04-30T16:08:47.449Z', + EndpointActions: { + action_id: '123', + completed_at: '2022-04-30T10:53:59.449Z', + data: { + command: 'get-file', + comment: '', + output: { + content: { + code: 'ra_get-file_success_done', + contents: [ + { + file_name: 'bad_file.txt', + path: '/some/path/bad_file.txt', + sha256: '9558c5cb39622e9b3653203e772b129d6c634e7dbd7af1b244352fc1d704601f', + size: 1234, + type: 'file', + }, + ], + zip_size: 123, + }, + type: 'json', + }, + }, + started_at: '2022-04-30T12:56:00.449Z', + }, + agent: { + id: 'agent-a', + }, + }, + }, + ], + }); + }); + + it('should return empty array with no responses exist', async () => { + applyActionListEsSearchMock(esClientMock, undefined, BaseDataGenerator.toEsSearchResponse([])); + + await expect(fetchActionResponses({ esClient: esClientMock })).resolves.toEqual({ data: [] }); + }); + + it('should query both fleet and endpoint indexes', async () => { + await fetchActionResponses({ esClient: esClientMock }); + const expectedQuery = { + query: { + bool: { + filter: [], + }, + }, + }; + + expect(esClientMock.search).toHaveBeenCalledWith( + { index: AGENT_ACTIONS_RESULTS_INDEX, size: ACTIONS_SEARCH_PAGE_SIZE, body: expectedQuery }, + { ignore: [404] } + ); + expect(esClientMock.search).toHaveBeenCalledWith( + { + index: ENDPOINT_ACTION_RESPONSES_INDEX_PATTERN, + size: ACTIONS_SEARCH_PAGE_SIZE, + body: expectedQuery, + }, + { ignore: [404] } + ); + }); + + it('should filter by agentIds', async () => { + await fetchActionResponses({ esClient: esClientMock, agentIds: ['a', 'b', 'c'] }); + const expectedQuery = { + query: { bool: { filter: [{ terms: { agent_id: ['a', 'b', 'c'] } }] } }, + }; + + expect(esClientMock.search).toHaveBeenCalledWith( + expect.objectContaining({ index: AGENT_ACTIONS_RESULTS_INDEX, body: expectedQuery }), + { ignore: [404] } + ); + expect(esClientMock.search).toHaveBeenCalledWith( + expect.objectContaining({ + index: ENDPOINT_ACTION_RESPONSES_INDEX_PATTERN, + body: expectedQuery, + }), + { ignore: [404] } + ); + }); + + it('should filter by action ids', async () => { + await fetchActionResponses({ esClient: esClientMock, actionIds: ['a', 'b', 'c'] }); + const expectedQuery = { + query: { bool: { filter: [{ terms: { action_id: ['a', 'b', 'c'] } }] } }, + }; + + expect(esClientMock.search).toHaveBeenCalledWith( + expect.objectContaining({ index: AGENT_ACTIONS_RESULTS_INDEX, body: expectedQuery }), + { ignore: [404] } + ); + expect(esClientMock.search).toHaveBeenCalledWith( + expect.objectContaining({ + index: ENDPOINT_ACTION_RESPONSES_INDEX_PATTERN, + body: expectedQuery, + }), + { ignore: [404] } + ); + }); + + it('should filter by both agent and action ids', async () => { + await fetchActionResponses({ + esClient: esClientMock, + agentIds: ['1', '2'], + actionIds: ['a', 'b', 'c'], + }); + const expectedQuery = { + query: { + bool: { + filter: [{ terms: { agent_id: ['1', '2'] } }, { terms: { action_id: ['a', 'b', 'c'] } }], + }, + }, + }; + + expect(esClientMock.search).toHaveBeenCalledWith( + expect.objectContaining({ index: AGENT_ACTIONS_RESULTS_INDEX, body: expectedQuery }), + { ignore: [404] } + ); + expect(esClientMock.search).toHaveBeenCalledWith( + expect.objectContaining({ + index: ENDPOINT_ACTION_RESPONSES_INDEX_PATTERN, + body: expectedQuery, + }), + { ignore: [404] } + ); + }); +}); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/fetch_action_responses.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/fetch_action_responses.ts new file mode 100644 index 0000000000000..7ed0bad9a42be --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/fetch_action_responses.ts @@ -0,0 +1,89 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { AGENT_ACTIONS_RESULTS_INDEX } from '@kbn/fleet-plugin/common'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { + EndpointActionResponse, + LogsEndpointActionResponse, +} from '../../../../common/endpoint/types'; +import { ACTIONS_SEARCH_PAGE_SIZE } from './constants'; +import { catchAndWrapError } from '../../utils'; +import { ENDPOINT_ACTION_RESPONSES_INDEX_PATTERN } from '../../../../common/endpoint/constants'; + +interface FetchActionResponsesOptions { + esClient: ElasticsearchClient; + /** List of specific action ids to filter for */ + actionIds?: string[]; + /** List of specific agent ids to filter for */ + agentIds?: string[]; +} + +interface FetchActionResponsesResult { + data: Array>; +} + +/** + * Fetch Response Action responses + */ +export const fetchActionResponses = async ({ + esClient, + actionIds = [], + agentIds = [], +}: FetchActionResponsesOptions): Promise => { + const filter = []; + + if (agentIds?.length) { + filter.push({ terms: { agent_id: agentIds } }); + } + if (actionIds.length) { + filter.push({ terms: { action_id: actionIds } }); + } + + const query: estypes.QueryDslQueryContainer = { + bool: { + filter, + }, + }; + + // Get the Action Response(s) from both the Fleet action response index and the Endpoint + // action response index. + // We query both indexes separately in order to ensure they are both queried - example if the + // Fleet actions responses index does not exist yet, ES would generate a `404` and would + // never actually query the Endpoint Actions index. With support for 3rd party response + // actions, we need to ensure that both indexes are queried. + const [fleetResponses, endpointResponses] = await Promise.all([ + // Responses in Fleet index + esClient + .search( + { + index: AGENT_ACTIONS_RESULTS_INDEX, + size: ACTIONS_SEARCH_PAGE_SIZE, + body: { query }, + }, + { ignore: [404] } + ) + .catch(catchAndWrapError), + + // Responses in Endpoint index + esClient + .search( + { + index: ENDPOINT_ACTION_RESPONSES_INDEX_PATTERN, + size: ACTIONS_SEARCH_PAGE_SIZE, + body: { query }, + }, + { ignore: [404] } + ) + .catch(catchAndWrapError), + ]); + + return { + data: [...(fleetResponses?.hits?.hits ?? []), ...(endpointResponses?.hits?.hits ?? [])], + }; +}; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/mocks.ts index a4536f54b92d7..0c5ac6cf38b38 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/mocks.ts @@ -9,6 +9,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClientMock } from '@kbn/core/server/mocks'; import { AGENT_ACTIONS_RESULTS_INDEX } from '@kbn/fleet-plugin/common'; import { Readable } from 'stream'; +import type { TransportRequestOptions } from '@elastic/transport'; import type { HapiReadableStream } from '../../../types'; import { EndpointActionGenerator } from '../../../../common/endpoint/data_generators/endpoint_action_generator'; import { FleetActionGenerator } from '../../../../common/endpoint/data_generators/fleet_action_generator'; @@ -146,15 +147,24 @@ export const applyActionListEsSearchMock = ( // @ts-expect-error incorrect type esClient.search.mockImplementation(async (...args) => { const params = args[0] ?? {}; + const options: TransportRequestOptions = args[1] ?? {}; const indexes = Array.isArray(params.index) ? params.index : [params.index]; if (indexes.includes(ENDPOINT_ACTIONS_INDEX)) { - return { body: { ...actionRequests } }; + if (options.meta) { + return { body: { ...actionRequests } }; + } + + return actionRequests; } else if ( indexes.includes(AGENT_ACTIONS_RESULTS_INDEX) || indexes.includes(ENDPOINT_ACTION_RESPONSES_INDEX_PATTERN) ) { - return { body: { ...actionResponses } }; + if (options.meta) { + return { body: { ...actionResponses } }; + } + + return actionResponses; } if (priorSearchMockImplementation) { diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/utils.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/utils.test.ts index b5c2119281e75..e63caeb222be8 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/utils.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/utils.test.ts @@ -8,6 +8,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { EndpointActionGenerator } from '../../../../common/endpoint/data_generators/endpoint_action_generator'; import { FleetActionGenerator } from '../../../../common/endpoint/data_generators/fleet_action_generator'; +import type { NormalizedActionRequest } from './utils'; import { categorizeActionResults, categorizeResponseResults, @@ -18,6 +19,7 @@ import { isLogsEndpointAction, isLogsEndpointActionResponse, mapToNormalizedActionRequest, + createActionDetailsRecord, } from './utils'; import type { ActivityLogAction, @@ -28,10 +30,12 @@ import type { EndpointActivityLogActionResponse, LogsEndpointAction, LogsEndpointActionResponse, + EndpointActionResponseDataOutput, } from '../../../../common/endpoint/types'; import { v4 as uuidv4 } from 'uuid'; import type { Results } from '../../routes/actions/mocks'; import { mockAuditLogSearchResult } from '../../routes/actions/mocks'; +import { ActivityLogItemTypes } from '../../../../common/endpoint/types'; describe('When using Actions service utilities', () => { let fleetActionGenerator: FleetActionGenerator; @@ -72,6 +76,8 @@ describe('When using Actions service utilities', () => { ) ).toEqual({ agents: ['6e6796b0-af39-4f12-b025-fcb06db499e5'], + agentType: 'endpoint', + hosts: {}, command: 'kill-process', comment: expect.any(String), createdAt: '2022-04-27T16:08:47.449Z', @@ -92,6 +98,8 @@ describe('When using Actions service utilities', () => { ) ).toEqual({ agents: ['90d62689-f72d-4a05-b5e3-500cad0dc366'], + agentType: 'endpoint', + hosts: {}, command: 'kill-process', comment: expect.any(String), createdAt: '2022-04-27T16:08:47.449Z', @@ -176,7 +184,7 @@ describe('When using Actions service utilities', () => { agent: { id: '123' }, EndpointActions: { completed_at: COMPLETED_AT, - data: { output: { type: 'json', content: { foo: 'bar' } } }, + data: { output: { type: 'json', content: { code: 'aaa' } } }, }, }, }, @@ -198,7 +206,7 @@ describe('When using Actions service utilities', () => { outputs: { '123': { content: { - foo: 'bar', + code: 'aaa', }, type: 'json', }, @@ -388,9 +396,18 @@ describe('When using Actions service utilities', () => { describe('with multiple agent ids', () => { let agentIds: string[]; let actionId: string; - let action123Responses: Array; - let action456Responses: Array; - let action789Responses: Array; + let action123Responses: Array< + | ActivityLogActionResponse + | EndpointActivityLogActionResponse + >; + let action456Responses: Array< + | ActivityLogActionResponse + | EndpointActivityLogActionResponse + >; + let action789Responses: Array< + | ActivityLogActionResponse + | EndpointActivityLogActionResponse + >; beforeEach(() => { agentIds = ['123', '456', '789']; @@ -605,11 +622,11 @@ describe('When using Actions service utilities', () => { it('should include output for agents for which the action was complete', () => { // Add output to the completed actions ( - action123Responses[1] as EndpointActivityLogActionResponse + action123Responses[1] as EndpointActivityLogActionResponse ).item.data.EndpointActions.data.output = { type: 'json', content: { - foo: 'bar', + code: 'bar', }, }; @@ -662,7 +679,7 @@ describe('When using Actions service utilities', () => { outputs: { '123': { content: { - foo: 'bar', + code: 'bar', }, type: 'json', }, @@ -955,4 +972,121 @@ describe('When using Actions service utilities', () => { ).toEqual({ isExpired: false, status: 'failed' }); }); }); + + describe('#createActionDetailsRecord()', () => { + let actionRequest: NormalizedActionRequest; + let actionResponses: Array; + let agentHostInfo: Record; + + beforeEach(() => { + actionRequest = { + agents: ['6e6796b0-af39-4f12-b025-fcb06db499e5'], + command: 'kill-process', + comment: 'kill this one', + createdAt: '2022-04-27T16:08:47.449Z', + createdBy: 'elastic', + expiration: '2022-04-29T16:08:47.449Z', + id: '90d62689-f72d-4a05-b5e3-500cad0dc366', + type: 'ACTION_REQUEST', + parameters: undefined, + agentType: 'endpoint', + hosts: {}, + }; + + actionResponses = [ + { + type: ActivityLogItemTypes.FLEET_RESPONSE, + item: { + id: actionRequest.id, + data: fleetActionGenerator.generateResponse({ + action_id: actionRequest.id, + agent_id: actionRequest.agents[0], + }), + }, + }, + + { + type: ActivityLogItemTypes.RESPONSE, + item: { + id: actionRequest.id, + data: endpointActionGenerator.generateResponse({ + agent: { id: actionRequest.agents }, + EndpointActions: { + action_id: actionRequest.id, + }, + }), + }, + }, + ]; + + agentHostInfo = { + [actionRequest.agents[0]]: 'host-a', + }; + }); + + it('should return expected action details record', () => { + expect(createActionDetailsRecord(actionRequest, actionResponses, agentHostInfo)).toEqual({ + action: '90d62689-f72d-4a05-b5e3-500cad0dc366', + id: '90d62689-f72d-4a05-b5e3-500cad0dc366', + agentType: 'endpoint', + agents: ['6e6796b0-af39-4f12-b025-fcb06db499e5'], + command: 'kill-process', + comment: 'kill this one', + completedAt: expect.any(String), + startedAt: '2022-04-27T16:08:47.449Z', + status: 'successful', + wasSuccessful: true, + errors: undefined, + createdBy: 'elastic', + isCompleted: true, + isExpired: false, + parameters: undefined, + agentState: { + '6e6796b0-af39-4f12-b025-fcb06db499e5': { + completedAt: expect.any(String), + isCompleted: true, + wasSuccessful: true, + }, + }, + hosts: { + '6e6796b0-af39-4f12-b025-fcb06db499e5': { + name: 'host-a', + }, + }, + outputs: { + '6e6796b0-af39-4f12-b025-fcb06db499e5': { + content: { + code: 'ra_get-file_success_done', + contents: [ + { + file_name: 'bad_file.txt', + path: '/some/path/bad_file.txt', + sha256: '9558c5cb39622e9b3653203e772b129d6c634e7dbd7af1b244352fc1d704601f', + size: 1234, + type: 'file', + }, + ], + zip_size: 123, + }, + type: 'json', + }, + }, + }); + }); + + it('should populate host name from action request', () => { + agentHostInfo = {}; + actionRequest.hosts[actionRequest.agents[0]] = { name: 'host-b' }; + + expect( + createActionDetailsRecord(actionRequest, actionResponses, agentHostInfo) + ).toMatchObject({ + hosts: { + '6e6796b0-af39-4f12-b025-fcb06db499e5': { + name: 'host-b', + }, + }, + }); + }); + }); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/utils.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/utils.ts index 1d16c944d2cef..b851b087c8231 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/utils.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/utils.ts @@ -8,7 +8,10 @@ import type { ElasticsearchClient } from '@kbn/core/server'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { EcsError } from '@kbn/ecs'; -import type { ResponseActionsApiCommandNames } from '../../../../common/endpoint/service/response_actions/constants'; +import type { + ResponseActionsApiCommandNames, + ResponseActionAgentType, +} from '../../../../common/endpoint/service/response_actions/constants'; import { ENDPOINT_ACTIONS_DS, ENDPOINT_ACTION_RESPONSES_DS, @@ -26,6 +29,8 @@ import type { EndpointActivityLogActionResponse, LogsEndpointAction, LogsEndpointActionResponse, + EndpointActionResponseDataOutput, + WithAllKeys, } from '../../../../common/endpoint/types'; import { ActivityLogItemTypes } from '../../../../common/endpoint/types'; import type { EndpointMetadataService } from '../metadata'; @@ -44,14 +49,15 @@ export const isLogsEndpointAction = ( * @param item */ export const isLogsEndpointActionResponse = ( - item: EndpointActionResponse | LogsEndpointActionResponse -): item is LogsEndpointActionResponse => { + item: EndpointActionResponse | LogsEndpointActionResponse +): item is LogsEndpointActionResponse => { return 'EndpointActions' in item && 'agent' in item; }; -interface NormalizedActionRequest { +export interface NormalizedActionRequest { id: string; type: 'ACTION_REQUEST'; + agentType: ResponseActionAgentType; expiration: string; agents: string[]; createdBy: string; @@ -63,6 +69,8 @@ interface NormalizedActionRequest { ruleId?: string; ruleName?: string; error?: EcsError; + /** Host info that might have been stored along with the Action Request (ex. 3rd party EDR actions) */ + hosts: ActionDetails['hosts']; } /** @@ -80,6 +88,7 @@ export const mapToNormalizedActionRequest = ( agents: Array.isArray(actionRequest.agent.id) ? actionRequest.agent.id : [actionRequest.agent.id], + agentType: actionRequest.EndpointActions.input_type, command: actionRequest.EndpointActions.data.command, comment: actionRequest.EndpointActions.data.comment, createdBy: actionRequest.user.id, @@ -92,12 +101,14 @@ export const mapToNormalizedActionRequest = ( ruleId: actionRequest.rule?.id, ruleName: actionRequest.rule?.name, error: actionRequest.error, + hosts: actionRequest.EndpointActions.data.hosts ?? {}, }; } // Else, it's a Fleet Endpoint Action record return { agents: actionRequest.agents, + agentType: actionRequest.input_type, command: actionRequest.data.command, comment: actionRequest.data.comment, createdBy: actionRequest.user_id, @@ -106,6 +117,7 @@ export const mapToNormalizedActionRequest = ( id: actionRequest.action_id, type, parameters: actionRequest.data.parameters, + hosts: {}, }; }; @@ -114,11 +126,15 @@ type ActionCompletionInfo = Pick< 'isCompleted' | 'completedAt' | 'wasSuccessful' | 'errors' | 'outputs' | 'agentState' >; -export const getActionCompletionInfo = ( +export const getActionCompletionInfo = < + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput +>( /** The normalized action request */ action: NormalizedActionRequest, /** List of action Log responses received for the action */ - actionResponses: Array + actionResponses: Array< + ActivityLogActionResponse | EndpointActivityLogActionResponse + > ): ActionCompletionInfo => { const agentIds = action.agents; const completedInfo: ActionCompletionInfo = { @@ -235,13 +251,15 @@ export const getActionStatus = ({ return { isExpired, status }; }; -interface NormalizedAgentActionResponse { +interface NormalizedAgentActionResponse< + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput +> { isCompleted: boolean; completedAt: undefined | string; wasSuccessful: boolean; errors: undefined | string[]; fleetResponse: undefined | ActivityLogActionResponse; - endpointResponse: undefined | EndpointActivityLogActionResponse; + endpointResponse: undefined | EndpointActivityLogActionResponse; } type ActionResponseByAgentId = Record; @@ -251,8 +269,12 @@ type ActionResponseByAgentId = Record; * value is a object having information about the action responses associated with that agent id * @param actionResponses */ -const mapActionResponsesByAgentId = ( - actionResponses: Array +const mapActionResponsesByAgentId = < + TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput +>( + actionResponses: Array< + ActivityLogActionResponse | EndpointActivityLogActionResponse + > ): ActionResponseByAgentId => { const response: ActionResponseByAgentId = {}; @@ -337,7 +359,9 @@ const mapActionResponsesByAgentId = ( * @param actionResponse */ const getAgentIdFromActionResponse = ( - actionResponse: ActivityLogActionResponse | EndpointActivityLogActionResponse + actionResponse: + | ActivityLogActionResponse + | EndpointActivityLogActionResponse ): string => { const responseData = actionResponse.item.data; @@ -524,3 +548,47 @@ export const getAgentHostNamesWithIds = async ({ return agentsMetadataInfo; }; + +export const createActionDetailsRecord = ( + actionRequest: NormalizedActionRequest, + actionResponses: Array, + agentHostInfo: Record +): T => { + const { isCompleted, completedAt, wasSuccessful, errors, outputs, agentState } = + getActionCompletionInfo(actionRequest, actionResponses); + + const { isExpired, status } = getActionStatus({ + expirationDate: actionRequest.expiration, + isCompleted, + wasSuccessful, + }); + + const actionDetails: WithAllKeys = { + action: actionRequest.id, + id: actionRequest.id, + agentType: actionRequest.agentType, + agents: actionRequest.agents, + hosts: actionRequest.agents.reduce((acc, id) => { + acc[id] = { name: agentHostInfo[id] || actionRequest.hosts[id]?.name || '' }; + return acc; + }, {}), + command: actionRequest.command, + startedAt: actionRequest.createdAt, + isCompleted, + completedAt, + wasSuccessful, + errors, + isExpired, + status, + outputs, + agentState, + createdBy: actionRequest.createdBy, + comment: actionRequest.comment, + parameters: actionRequest.parameters, + alertIds: actionRequest.alertIds, + ruleId: actionRequest.ruleId, + ruleName: actionRequest.ruleName, + }; + + return actionDetails as T; +}; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/feature_keys.ts b/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/feature_keys.ts new file mode 100644 index 0000000000000..b7e8b8ab87548 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/feature_keys.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ResponseActionsApiCommandNames } from '../../../../common/endpoint/service/response_actions/constants'; + +export const FEATURE_KEYS = { + HOST_ISOLATION: 'Host isolation', + HOST_ISOLATION_EXCEPTION: 'Host isolation exception', + HOST_ISOLATION_EXCEPTION_BY_POLICY: 'Host isolation exception by policy', + TRUSTED_APP_BY_POLICY: 'Trusted app by policy', + EVENT_FILTERS_BY_POLICY: 'Event filters by policy', + BLOCKLIST_BY_POLICY: 'Blocklists by policy', + RANSOMWARE_PROTECTION: 'Ransomeware protection', + MEMORY_THREAT_PROTECTION: 'Memory threat protection', + BEHAVIOR_PROTECTION: 'Behavior protection', + KILL_PROCESS: 'Kill process', + SUSPEND_PROCESS: 'Suspend process', + RUNNING_PROCESSES: 'Get running processes', + GET_FILE: 'Get file', + UPLOAD: 'Upload file', + EXECUTE: 'Execute command', + ALERTS_BY_PROCESS_ANCESTRY: 'Get related alerts by process ancestry', + ENDPOINT_EXCEPTIONS: 'Endpoint exceptions', +} as const; + +export type FeatureKeys = keyof typeof FEATURE_KEYS; + +const RESPONSE_ACTIONS_FEATURE_KEY: Readonly> = + { + isolate: 'HOST_ISOLATION', + unisolate: 'HOST_ISOLATION', + 'kill-process': 'KILL_PROCESS', + 'suspend-process': 'SUSPEND_PROCESS', + 'running-processes': 'RUNNING_PROCESSES', + 'get-file': 'GET_FILE', + execute: 'EXECUTE', + upload: 'UPLOAD', + }; + +export const getResponseActionFeatureKey = ( + responseAction: ResponseActionsApiCommandNames +): FeatureKeys | undefined => { + return RESPONSE_ACTIONS_FEATURE_KEY[responseAction]; +}; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/index.ts b/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/index.ts index 5c880f67847ed..8b58f62e45e1a 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/index.ts @@ -6,6 +6,6 @@ */ import { FeatureUsageService } from './service'; -export type { FeatureKeys } from './service'; +export type { FeatureKeys } from './feature_keys'; export const featureUsageService = new FeatureUsageService(); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/mocks.ts index 1eb1b3b82371a..d032085bfe403 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/mocks.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { getResponseActionFeatureKey } from './feature_keys'; import type { FeatureUsageService } from './service'; import type { PolicyData } from '../../../../common/endpoint/types'; @@ -13,6 +14,7 @@ export function createFeatureUsageServiceMock() { setup: jest.fn(), start: jest.fn(), notifyUsage: jest.fn(), + getResponseActionFeatureKey: jest.fn(getResponseActionFeatureKey), } as unknown as jest.Mocked; } diff --git a/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/service.ts b/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/service.ts index ffebaac4420fc..a236d6b569e23 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/service.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/service.ts @@ -7,37 +7,19 @@ import type { Values } from '@kbn/utility-types'; import type { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/server'; - -const FEATURES = { - HOST_ISOLATION: 'Host isolation', - HOST_ISOLATION_EXCEPTION: 'Host isolation exception', - HOST_ISOLATION_EXCEPTION_BY_POLICY: 'Host isolation exception by policy', - TRUSTED_APP_BY_POLICY: 'Trusted app by policy', - EVENT_FILTERS_BY_POLICY: 'Event filters by policy', - BLOCKLIST_BY_POLICY: 'Blocklists by policy', - RANSOMWARE_PROTECTION: 'Ransomeware protection', - MEMORY_THREAT_PROTECTION: 'Memory threat protection', - BEHAVIOR_PROTECTION: 'Behavior protection', - KILL_PROCESS: 'Kill process', - SUSPEND_PROCESS: 'Suspend process', - RUNNING_PROCESSES: 'Get running processes', - GET_FILE: 'Get file', - EXECUTE: 'Execute command', - ALERTS_BY_PROCESS_ANCESTRY: 'Get related alerts by process ancestry', - ENDPOINT_EXCEPTIONS: 'Endpoint exceptions', -} as const; - -export type FeatureKeys = keyof typeof FEATURES; +import type { ResponseActionsApiCommandNames } from '../../../../common/endpoint/service/response_actions/constants'; +import type { FeatureKeys } from './feature_keys'; +import { getResponseActionFeatureKey, FEATURE_KEYS } from './feature_keys'; export class FeatureUsageService { private licensingPluginStart: LicensingPluginStart | undefined; - private get notify(): (featureName: Values) => void { + private get notify(): (featureName: Values) => void { return this.licensingPluginStart?.featureUsage.notifyUsage || function () {}; } public setup(licensingPluginSetup: LicensingPluginSetup): void { - Object.values(FEATURES).map((featureValue) => + Object.values(FEATURE_KEYS).map((featureValue) => licensingPluginSetup.featureUsage.register(featureValue, 'platinum') ); } @@ -47,6 +29,12 @@ export class FeatureUsageService { } public notifyUsage(featureKey: FeatureKeys): void { - this.notify(FEATURES[featureKey]); + this.notify(FEATURE_KEYS[featureKey]); + } + + public getResponseActionFeatureKey( + responseAction: ResponseActionsApiCommandNames + ): FeatureKeys | undefined { + return getResponseActionFeatureKey(responseAction); } } diff --git a/x-pack/plugins/security_solution/server/endpoint/utils/action_list_helpers.test.ts b/x-pack/plugins/security_solution/server/endpoint/utils/action_list_helpers.test.ts index cfee4407500bd..c552cb3601534 100644 --- a/x-pack/plugins/security_solution/server/endpoint/utils/action_list_helpers.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/utils/action_list_helpers.test.ts @@ -5,15 +5,13 @@ * 2.0. */ -import { v4 as uuidv4 } from 'uuid'; import type { ScopedClusterClientMock } from '@kbn/core/server/mocks'; import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; import { applyActionListEsSearchMock, createActionRequestsEsSearchResultsMock, - createActionResponsesEsSearchResultsMock, } from '../services/actions/mocks'; -import { getActions, getActionResponses } from './action_list_helpers'; +import { getActions } from './action_list_helpers'; describe('action helpers', () => { let mockScopedEsClient: ScopedClusterClientMock; @@ -36,18 +34,7 @@ describe('action helpers', () => { must: [ { bool: { - filter: [ - { - term: { - input_type: 'endpoint', - }, - }, - { - term: { - type: 'INPUT_ACTION', - }, - }, - ], + filter: [], }, }, ], @@ -96,16 +83,6 @@ describe('action helpers', () => { { bool: { filter: [ - { - term: { - input_type: 'endpoint', - }, - }, - { - term: { - type: 'INPUT_ACTION', - }, - }, { range: { '@timestamp': { @@ -210,16 +187,6 @@ describe('action helpers', () => { { bool: { filter: [ - { - term: { - input_type: 'endpoint', - }, - }, - { - term: { - type: 'INPUT_ACTION', - }, - }, { range: { '@timestamp': { @@ -307,97 +274,4 @@ describe('action helpers', () => { expect(actions.actionRequests?.body?.hits?.hits[0]._source?.agent.id).toEqual('agent-a'); }); }); - - describe('#getActionResponses', () => { - it('should use base filters correctly when no other filter options provided', async () => { - const esClient = mockScopedEsClient.asInternalUser; - applyActionListEsSearchMock(esClient); - await getActionResponses({ esClient, actionIds: [] }); - - expect(esClient.search).toHaveBeenCalledWith( - { - body: { - query: { - bool: { - filter: [], - }, - }, - }, - from: 0, - index: ['.fleet-actions-results', '.logs-endpoint.action.responses-*'], - size: 10000, - }, - { - headers: { - 'X-elastic-product-origin': 'fleet', - }, - ignore: [404], - meta: true, - } - ); - }); - it('should query with actionIds and elasticAgentIds when provided', async () => { - const actionIds = [uuidv4(), uuidv4()]; - const elasticAgentIds = ['123', '456']; - const esClient = mockScopedEsClient.asInternalUser; - applyActionListEsSearchMock(esClient); - await getActionResponses({ esClient, actionIds, elasticAgentIds }); - - expect(esClient.search).toHaveBeenCalledWith( - { - body: { - query: { - bool: { - filter: [ - { - terms: { - agent_id: elasticAgentIds, - }, - }, - { - terms: { - action_id: actionIds, - }, - }, - ], - }, - }, - }, - from: 0, - index: ['.fleet-actions-results', '.logs-endpoint.action.responses-*'], - size: 10000, - }, - { - headers: { - 'X-elastic-product-origin': 'fleet', - }, - ignore: [404], - meta: true, - } - ); - }); - it('should return expected output', async () => { - const esClient = mockScopedEsClient.asInternalUser; - const actionRes = createActionResponsesEsSearchResultsMock(); - applyActionListEsSearchMock(esClient, undefined, actionRes); - - const responses = await getActionResponses({ - esClient, - actionIds: ['123'], - elasticAgentIds: ['agent-a'], - }); - - const responseHits = responses.body.hits.hits; - - expect(responseHits.length).toEqual(2); - expect( - responseHits.map((e) => e._index).filter((e) => e.includes('.fleet-actions-results')).length - ).toEqual(1); - expect( - responseHits - .map((e) => e._index) - .filter((e) => e.includes('.logs-endpoint.action.responses')).length - ).toEqual(1); - }); - }); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/utils/action_list_helpers.ts b/x-pack/plugins/security_solution/server/endpoint/utils/action_list_helpers.ts index c74373311cf72..4c1d7e584f214 100644 --- a/x-pack/plugins/security_solution/server/endpoint/utils/action_list_helpers.ts +++ b/x-pack/plugins/security_solution/server/endpoint/utils/action_list_helpers.ts @@ -5,19 +5,13 @@ * 2.0. */ -import type { ElasticsearchClient } from '@kbn/core/server'; import type { SearchRequest } from '@kbn/data-plugin/public'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { TransportResult } from '@elastic/elasticsearch'; import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; import { ENDPOINT_ACTIONS_INDEX } from '../../../common/endpoint/constants'; -import type { - LogsEndpointAction, - EndpointActionResponse, - LogsEndpointActionResponse, -} from '../../../common/endpoint/types'; -import { ACTIONS_SEARCH_PAGE_SIZE, ACTION_RESPONSE_INDICES } from '../services/actions/constants'; +import type { LogsEndpointAction } from '../../../common/endpoint/types'; import { getDateFilters } from '../services/actions/utils'; import { catchAndWrapError } from './wrap_errors'; import type { GetActionDetailsListParam } from '../services/actions/action_list'; @@ -61,12 +55,7 @@ export const getActions = async ({ const dateFilters = getDateFilters({ startDate, endDate }); - const actionsFilters = [ - { term: { input_type: 'endpoint' } }, - { term: { type: 'INPUT_ACTION' } }, - ...dateFilters, - ...additionalFilters, - ]; + const actionsFilters = [...dateFilters, ...additionalFilters]; const must: SearchRequest = [ { @@ -144,53 +133,3 @@ export const getActions = async ({ return { actionIds, actionRequests }; }; - -export const getActionResponses = async ({ - actionIds, - elasticAgentIds, - esClient, -}: { - actionIds: string[]; - elasticAgentIds?: string[]; - esClient: ElasticsearchClient; -}): Promise< - TransportResult< - estypes.SearchResponse, - unknown - > -> => { - const filter = []; - if (elasticAgentIds?.length) { - filter.push({ terms: { agent_id: elasticAgentIds } }); - } - if (actionIds.length) { - filter.push({ terms: { action_id: actionIds } }); - } - - const responsesSearchQuery: SearchRequest = { - index: ACTION_RESPONSE_INDICES, - size: ACTIONS_SEARCH_PAGE_SIZE, - from: 0, - body: { - query: { - bool: { - filter: filter.length ? filter : [], - }, - }, - }, - }; - - const actionResponses: TransportResult< - estypes.SearchResponse, - unknown - > = await esClient - .search(responsesSearchQuery, { - ...queryOptions, - headers: { - 'X-elastic-product-origin': 'fleet', - }, - meta: true, - }) - .catch(catchAndWrapError); - return actionResponses; -}; diff --git a/x-pack/plugins/security_solution/server/endpoint/utils/dump.ts b/x-pack/plugins/security_solution/server/endpoint/utils/stringify.ts similarity index 88% rename from x-pack/plugins/security_solution/server/endpoint/utils/dump.ts rename to x-pack/plugins/security_solution/server/endpoint/utils/stringify.ts index ae05b73fac05a..bd61861b6b9fc 100644 --- a/x-pack/plugins/security_solution/server/endpoint/utils/dump.ts +++ b/x-pack/plugins/security_solution/server/endpoint/utils/stringify.ts @@ -13,6 +13,6 @@ import { inspect } from 'util'; * @param depth */ // eslint-disable-next-line @typescript-eslint/no-explicit-any -export const dump = (content: any, depth = 8): string => { +export const stringify = (content: any, depth = 8): string => { return inspect(content, { depth }); }; diff --git a/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.ts b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.ts index 4630ad9edec07..4d92f5f2c9dd8 100644 --- a/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.ts +++ b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.ts @@ -11,6 +11,7 @@ import { isEqual } from 'lodash/fp'; import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; import { OperatingSystem } from '@kbn/securitysolution-utils'; +import type { FeatureKeys } from '../../../endpoint/services'; import type { EndpointAuthz } from '../../../../common/endpoint/types/authz'; import type { EndpointAppContextService } from '../../../endpoint/endpoint_app_context_services'; import type { ExceptionItemLikeOptions } from '../types'; @@ -21,7 +22,6 @@ import { } from '../../../../common/endpoint/service/artifacts'; import { EndpointArtifactExceptionValidationError } from './errors'; import { EndpointExceptionsValidationError } from './endpoint_exception_errors'; -import type { FeatureKeys } from '../../../endpoint/services/feature_usage/service'; export const BasicEndpointExceptionDataSchema = schema.object( { From 0a90b66ed37936086ce272424124fa51ee98aa14 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Thu, 4 Jan 2024 09:35:15 -0600 Subject: [PATCH 017/100] skip suite failing es promotion (#172984) --- x-pack/test/functional/apps/aiops/change_point_detection.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/aiops/change_point_detection.ts b/x-pack/test/functional/apps/aiops/change_point_detection.ts index 787d1b31df115..158d9a9c10cd0 100644 --- a/x-pack/test/functional/apps/aiops/change_point_detection.ts +++ b/x-pack/test/functional/apps/aiops/change_point_detection.ts @@ -16,7 +16,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // aiops lives in the ML UI so we need some related services. const ml = getService('ml'); - describe('change point detection', async function () { + // Failing ES Promotion: https://github.com/elastic/kibana/issues/172984 + describe.skip('change point detection', async function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); await ml.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); From 1182ce678c3b190aa5172f2b473db0d84ba12f5d Mon Sep 17 00:00:00 2001 From: jennypavlova Date: Thu, 4 Jan 2024 17:09:09 +0100 Subject: [PATCH 018/100] [ObsUX][Profiling, Infra] Add NEW badge to the Profiling tab (#174242) Closes #173156 ## Summary This PR adds a `NEW` badge to the profiling tab and changes the profiling prompt badge color to pink ## Testing The badges can be checked on the node details page and inside the host details flyout: ![image](https://github.com/elastic/kibana/assets/14139027/30f4ca24-b460-4fe9-8c2c-372e435a1c64) ![image](https://github.com/elastic/kibana/assets/14139027/423232b2-fc2e-4718-a089-180157db22da) --- .../asset_details_tabs.tsx | 3 +++ .../overview/kpis/cpu_profiling_prompt.tsx | 8 ++------ .../public/components/asset_details/types.ts | 1 + .../infra/public/components/new_badge.tsx | 18 ++++++++++++++++++ 4 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 x-pack/plugins/infra/public/components/new_badge.tsx diff --git a/x-pack/plugins/infra/public/common/asset_details_config/asset_details_tabs.tsx b/x-pack/plugins/infra/public/common/asset_details_config/asset_details_tabs.tsx index 312ed7eb04a98..2bc3d5661e22b 100644 --- a/x-pack/plugins/infra/public/common/asset_details_config/asset_details_tabs.tsx +++ b/x-pack/plugins/infra/public/common/asset_details_config/asset_details_tabs.tsx @@ -6,7 +6,9 @@ */ import { i18n } from '@kbn/i18n'; +import React from 'react'; import { ContentTabIds, type Tab } from '../../components/asset_details/types'; +import { NewBadge } from '../../components/new_badge'; export const commonFlyoutTabs: Tab[] = [ { @@ -32,6 +34,7 @@ export const commonFlyoutTabs: Tab[] = [ name: i18n.translate('xpack.infra.metrics.nodeDetails.tabs.profiling', { defaultMessage: 'Universal Profiling', }), + append: , }, { id: ContentTabIds.LOGS, diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/cpu_profiling_prompt.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/cpu_profiling_prompt.tsx index 54651b46bcce8..256ef447f8709 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/cpu_profiling_prompt.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/cpu_profiling_prompt.tsx @@ -8,8 +8,8 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiButtonEmpty } from '@elastic/eui'; -import { EuiBadge } from '@elastic/eui'; import { EuiFlexGroup } from '@elastic/eui'; +import { NewBadge } from '../../../../new_badge'; import { useProfilingIntegrationSetting } from '../../../../../hooks/use_profiling_integration_setting'; import { useTabSwitcherContext } from '../../../hooks/use_tab_switcher'; @@ -28,11 +28,7 @@ export function CpuProfilingPrompt() { gutterSize="s" data-test-subj="infraAssetDetailsCPUProfilingPrompt" > - - {i18n.translate('xpack.infra.cpuProfilingPrompt.newBadgeLabel', { - defaultMessage: 'NEW', - })} - + {i18n.translate('xpack.infra.cpuProfilingPrompt.promptText', { defaultMessage: 'View CPU Breakdown using', diff --git a/x-pack/plugins/infra/public/components/asset_details/types.ts b/x-pack/plugins/infra/public/components/asset_details/types.ts index dd3ae9af9d62e..346eda2bb3c32 100644 --- a/x-pack/plugins/infra/public/components/asset_details/types.ts +++ b/x-pack/plugins/infra/public/components/asset_details/types.ts @@ -60,6 +60,7 @@ export type RenderMode = FlyoutProps | FullPageProps; export interface Tab { id: ContentTabIds; name: string; + append?: JSX.Element; } export type LinkOptions = 'alertRule' | 'nodeDetails' | 'apmServices'; diff --git a/x-pack/plugins/infra/public/components/new_badge.tsx b/x-pack/plugins/infra/public/components/new_badge.tsx new file mode 100644 index 0000000000000..efbe026d8b7aa --- /dev/null +++ b/x-pack/plugins/infra/public/components/new_badge.tsx @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiBadge } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; + +export const NewBadge = () => ( + + {i18n.translate('xpack.infra.newBadgeLabel', { + defaultMessage: 'NEW', + })} + +); From 9cb830fe9a021cda1d091effbe3e0cd300220969 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Thu, 4 Jan 2024 09:16:03 -0700 Subject: [PATCH 019/100] Fix saved query update test (#173576) ## Summary Fixes https://github.com/elastic/kibana/issues/173094. Relying on the text from the toast notification was problematic because sometimes the toast would already have disappeared by the time the check was happening. Instead, this updates the test to refresh and check the saved query list for the updated saved query. Flaky test runner: https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/4750 ### Checklist Delete any items that are not applicable to this PR. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### Risk Matrix Delete this section if it is not applicable to this PR. Before closing this PR, invite QA, stakeholders, and other developers to identify risks that should be tested prior to the change/feature release. When forming the risk matrix, consider some of the following examples and how they may potentially impact the change: | Risk | Probability | Severity | Mitigation/Notes | |---------------------------|-------------|----------|-------------------------| | Multiple Spaces—unexpected behavior in non-default Kibana Space. | Low | High | Integration tests will verify that all features are still supported in non-default Kibana Space and when user switches between spaces. | | Multiple nodes—Elasticsearch polling might have race conditions when multiple Kibana nodes are polling for the same tasks. | High | Low | Tasks are idempotent, so executing them multiple times will not result in logical error, but will degrade performance. To test for this case we add plenty of unit tests around this logic and document manual testing procedure. | | Code should gracefully handle cases when feature X or plugin Y are disabled. | Medium | High | Unit tests will verify that any feature flag or plugin combination still results in our service operational. | | [See more potential risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) | ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --- .../functional/apps/discover/saved_queries.ts | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/x-pack/test/functional/apps/discover/saved_queries.ts b/x-pack/test/functional/apps/discover/saved_queries.ts index 466524f4dbf80..3daf70e3f560c 100644 --- a/x-pack/test/functional/apps/discover/saved_queries.ts +++ b/x-pack/test/functional/apps/discover/saved_queries.ts @@ -5,7 +5,6 @@ * 2.0. */ -import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { @@ -13,7 +12,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); const spaces = getService('spaces'); - const toasts = getService('toasts'); const PageObjects = getPageObjects([ 'common', 'discover', @@ -26,8 +24,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const savedQueryName = 'shared-saved-query'; const destinationSpaceId = 'nondefaultspace'; - // Failing: See https://github.com/elastic/kibana/issues/173094 - describe.skip('Discover Saved Queries', () => { + describe('Discover Saved Queries', () => { before('initialize tests', async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); await kibanaServer.importExport.load( @@ -53,6 +50,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // Navigate to Discover & create a saved query await PageObjects.common.navigateToApp('discover'); await queryBar.setQuery('response:200'); + await queryBar.submitQuery(); await savedQueryManagementComponent.saveNewQuery(savedQueryName, '', true, false); await savedQueryManagementComponent.savedQueryExistOrFail(savedQueryName); await savedQueryManagementComponent.closeSavedQueryManagementComponent(); @@ -76,24 +74,26 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('updates a saved query', async () => { + const name = `${savedQueryName}-update`; + // Navigate to Discover & create a saved query await PageObjects.common.navigateToApp('discover'); await queryBar.setQuery('response:200'); - await savedQueryManagementComponent.saveNewQuery(savedQueryName, '', true, false); - await savedQueryManagementComponent.savedQueryExistOrFail(savedQueryName); + await queryBar.submitQuery(); + await savedQueryManagementComponent.saveNewQuery(name, '', true, false); + await savedQueryManagementComponent.savedQueryExistOrFail(name); await savedQueryManagementComponent.closeSavedQueryManagementComponent(); - // Navigate to Discover & create a saved query + // Update the saved query await queryBar.setQuery('response:404'); + await queryBar.submitQuery(); await savedQueryManagementComponent.updateCurrentlyLoadedQuery('', true, false); - // Expect to see a success toast - const successToast = await toasts.getToastElement(1); - const successText = await successToast.getVisibleText(); - expect(successText).to.equal(`Your query "${savedQueryName}" was saved`); - + // Navigate to Discover ensure updated query exists await PageObjects.common.navigateToApp('discover'); - await savedQueryManagementComponent.deleteSavedQuery(savedQueryName); + await savedQueryManagementComponent.savedQueryExistOrFail(name); + await savedQueryManagementComponent.closeSavedQueryManagementComponent(); + await savedQueryManagementComponent.deleteSavedQuery(name); }); }); }); From 615e3f554d13d9122142bc521b54285d48b9149a Mon Sep 17 00:00:00 2001 From: Jon Date: Thu, 4 Jan 2024 11:19:38 -0600 Subject: [PATCH 020/100] [build] Upload CDN assets (#173159) This uploads CDN assets to a GCS bucket on commit and after all tests have passed. This will run on pull requests with `ci:project-deploy-*` and `ci:build-serverless-image` labels, and on `main`. Assets will include the first 12 digits of the commit sha as a base path. --- .buildkite/scripts/lifecycle/pre_command.sh | 6 ++++++ .../scripts/steps/artifacts/docker_image.sh | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/.buildkite/scripts/lifecycle/pre_command.sh b/.buildkite/scripts/lifecycle/pre_command.sh index 9b19e5e82da84..c14325efaa2a5 100755 --- a/.buildkite/scripts/lifecycle/pre_command.sh +++ b/.buildkite/scripts/lifecycle/pre_command.sh @@ -142,6 +142,12 @@ export SYNTHETICS_REMOTE_KIBANA_URL DEPLOY_TAGGER_SLACK_WEBHOOK_URL=${DEPLOY_TAGGER_SLACK_WEBHOOK_URL:-"$(vault_get kibana-serverless-release-tools DEPLOY_TAGGER_SLACK_WEBHOOK_URL)"} export DEPLOY_TAGGER_SLACK_WEBHOOK_URL +GCS_SA_CDN_QA_KEY="$(vault_get gcs-sa-cdn-qa key)" +export GCS_SA_CDN_QA_KEY + +GCS_SA_CDN_QA_BUCKET="$(vault_get gcs-sa-cdn-qa bucket)" +export GCS_SA_CDN_QA_BUCKET + # Setup Failed Test Reporter Elasticsearch credentials { TEST_FAILURES_ES_CLOUD_ID=$(vault_get failed_tests_reporter_es cloud_id) diff --git a/.buildkite/scripts/steps/artifacts/docker_image.sh b/.buildkite/scripts/steps/artifacts/docker_image.sh index 0518e17f6524e..864bc26805fbb 100755 --- a/.buildkite/scripts/steps/artifacts/docker_image.sh +++ b/.buildkite/scripts/steps/artifacts/docker_image.sh @@ -26,7 +26,7 @@ if docker manifest inspect $KIBANA_IMAGE &> /dev/null; then exit 1 fi -echo "--- Build images" +echo "--- Build Kibana" node scripts/build \ --debug \ --release \ @@ -37,8 +37,7 @@ node scripts/build \ --skip-docker-ubuntu \ --skip-docker-ubi \ --skip-docker-cloud \ - --skip-docker-contexts \ - --skip-cdn-assets + --skip-docker-contexts echo "--- Tag images" docker rmi "$KIBANA_IMAGE" @@ -88,12 +87,21 @@ fi echo "--- Build dependencies report" node scripts/licenses_csv_report "--csv=target/dependencies-$GIT_ABBREV_COMMIT.csv" -echo "--- Upload artifacts" +echo "--- Upload CDN assets" cd target +gcloud auth activate-service-account --key-file <(echo "$GCS_SA_CDN_QA_KEY") + +CDN_ASSETS_FOLDER=$(mktemp -d) +tar -xf "kibana-$BASE_VERSION-cdn-assets.tar.gz" -C "$CDN_ASSETS_FOLDER" --strip=1 + +gsutil -m cp -r "$CDN_ASSETS_FOLDER/*" "gs://$GCS_SA_CDN_QA_BUCKET/$GIT_ABBREV_COMMIT" + +echo "--- Upload archives" buildkite-agent artifact upload "kibana-$BASE_VERSION-linux-x86_64.tar.gz" buildkite-agent artifact upload "kibana-$BASE_VERSION-linux-aarch64.tar.gz" buildkite-agent artifact upload "kibana-$BASE_VERSION-docker-image.tar.gz" buildkite-agent artifact upload "kibana-$BASE_VERSION-docker-image-aarch64.tar.gz" +buildkite-agent artifact upload "kibana-$BASE_VERSION-cdn-assets.tar.gz" buildkite-agent artifact upload "dependencies-$GIT_ABBREV_COMMIT.csv" cd - From 7034f823d8446933b30f3d8236ce2ed75e441d8d Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Thu, 4 Jan 2024 19:22:45 +0200 Subject: [PATCH 021/100] [Lens] Fixes palette container to be full width (#174275) ## Summary Closes https://github.com/elastic/kibana/issues/174270 Fullwidth color mapping row image --- .../lens/public/visualizations/partition/dimension_editor.tsx | 1 + .../public/visualizations/tagcloud/tags_dimension_editor.tsx | 1 + .../visualizations/xy/xy_config_panel/dimension_editor.tsx | 1 + 3 files changed, 3 insertions(+) diff --git a/x-pack/plugins/lens/public/visualizations/partition/dimension_editor.tsx b/x-pack/plugins/lens/public/visualizations/partition/dimension_editor.tsx index e88d354acf68b..7cf4c6bfff66b 100644 --- a/x-pack/plugins/lens/public/visualizations/partition/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/visualizations/partition/dimension_editor.tsx @@ -140,6 +140,7 @@ export function DimensionEditor(props: DimensionEditorProps) { defaultMessage: 'Color mapping', })} style={{ alignItems: 'center' }} + fullWidth > Date: Thu, 4 Jan 2024 18:24:09 +0100 Subject: [PATCH 022/100] [Defend Workflows][FTR] Reenable trusted apps list FTR (#174186) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Closes #171481 This PR enables Trusted Apps List FTR - they were flaky in Serverless environment in November, but now passed 250 times perfectly. - 50x https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/4741 50/50 ✅ - 200x https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/4746 200/200 ✅ --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../apps/integrations/trusted_apps_list.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/x-pack/test/security_solution_endpoint/apps/integrations/trusted_apps_list.ts b/x-pack/test/security_solution_endpoint/apps/integrations/trusted_apps_list.ts index 1d48a415b1577..e00dde08d58fb 100644 --- a/x-pack/test/security_solution_endpoint/apps/integrations/trusted_apps_list.ts +++ b/x-pack/test/security_solution_endpoint/apps/integrations/trusted_apps_list.ts @@ -16,8 +16,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const browser = getService('browser'); const endpointTestResources = getService('endpointTestResources'); - // FLAKY: https://github.com/elastic/kibana/issues/171481 - describe.skip('When on the Trusted Apps list', function () { + describe('When on the Trusted Apps list', function () { targetTags(this, ['@ess', '@serverless']); let indexedData: IndexedHostsAndAlertsResponse; @@ -34,8 +33,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.missingOrFail('header-page-title'); }); - // FLAKY: https://github.com/elastic/kibana/issues/171481 - it.skip('should be able to add a new trusted app and remove it', async () => { + it('should be able to add a new trusted app and remove it', async () => { const SHA256 = 'A4370C0CF81686C0B696FA6261c9d3e0d810ae704ab8301839dffd5d5112f476'; // Add it From 0515829a9e50740357c0226fd1cb5081a273ccd3 Mon Sep 17 00:00:00 2001 From: Tre Date: Thu, 4 Jan 2024 17:58:17 +0000 Subject: [PATCH 023/100] [FTR] Move find service to shared location (#173874) ## Summary Refactoring general ui service to a kbn package. Resolves an [Appex QA](https://github.com/elastic/appex-qa-team) issue. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .eslintrc.js | 2 +- .../index.ts | 12 ++++++++++++ .../services/all.ts | 4 ++++ .../services}/find.ts | 10 ++++++---- .../services/ftr_provider_context.ts | 7 ++++++- .../config.js | 0 .../several_nested_window_size_changes/test.js | 0 .../several_nested_window_size_changes/test2.js | 0 .../test3.1.js | 0 .../several_nested_window_size_changes/test3.js | 0 .../__tests__/remote_default_window_size.js | 7 +++++-- .../services/remote/browsers.ts | 0 .../services/remote/create_stdout_stream.ts | 0 .../services/remote/index.ts | 2 ++ .../services/remote/network_profiles.ts | 0 .../services/remote/poll_for_log_entry.ts | 0 .../remote/prevent_parallel_calls.test.js | 0 .../services/remote/prevent_parallel_calls.ts | 0 .../services/remote/remote.ts | 2 +- .../services/remote/webdriver.ts | 0 .../web_element_wrapper/custom_cheerio_api.ts | 0 .../services}/web_element_wrapper/index.ts | 0 .../scroll_into_view_if_necessary.js | 2 +- .../web_element_wrapper/web_element_wrapper.ts | 2 +- .../tsconfig.json | 17 +++++++---------- .../types.ts | 0 test/examples/search/warnings.ts | 2 +- .../discover/group1/_discover_accessibility.ts | 2 +- .../apps/kibana_overview/_analytics.ts | 2 +- .../management/data_views/_field_formatter.ts | 2 +- test/functional/page_objects/console_page.ts | 2 +- .../page_objects/dashboard_page_controls.ts | 2 +- test/functional/page_objects/discover_page.ts | 2 +- .../page_objects/legacy/data_table_vis.ts | 2 +- test/functional/page_objects/tag_cloud_page.ts | 2 +- test/functional/page_objects/time_picker.ts | 2 +- test/functional/page_objects/timelion_page.ts | 2 +- .../page_objects/visual_builder_page.ts | 2 +- test/functional/services/combo_box.ts | 2 +- test/functional/services/common/browser.ts | 8 ++++---- test/functional/services/common/index.ts | 1 - test/functional/services/common/screenshots.ts | 2 +- .../functional/services/common/test_subjects.ts | 3 +-- .../services/dashboard/expectations.ts | 2 +- .../services/dashboard/panel_actions.ts | 2 +- .../dashboard/panel_drilldown_actions.ts | 2 +- .../services/dashboard/panel_settings.ts | 2 +- test/functional/services/data_grid.ts | 2 +- test/functional/services/doc_table.ts | 2 +- test/functional/services/index.ts | 4 ---- .../functional/services/saved_objects_finder.ts | 2 +- .../services/visualizations/elastic_chart.ts | 2 +- .../apps/group1/dashboard_panel_options.ts | 2 +- .../functional/apps/discover/visualize_field.ts | 2 +- x-pack/test/functional/apps/infra/hosts_view.ts | 2 +- .../dataset_selector.ts | 2 +- .../test/functional/page_objects/graph_page.ts | 2 +- .../functional/page_objects/infra_hosts_view.ts | 2 +- .../page_objects/infra_metrics_explorer.ts | 2 +- .../page_objects/ingest_pipelines_page.ts | 2 +- .../test/functional/page_objects/lens_page.ts | 2 +- .../page_objects/navigational_search.ts | 2 +- .../page_objects/observability_log_explorer.ts | 2 +- .../page_objects/tag_management_page.ts | 2 +- x-pack/test/functional/services/cases/list.ts | 2 +- .../services/infra_source_configuration_form.ts | 2 +- .../services/logs_ui/log_entry_categories.ts | 2 +- .../services/logs_ui/log_entry_rate.ts | 2 +- .../functional/services/logs_ui/log_stream.ts | 2 +- .../services/ml/common_table_service.ts | 2 +- x-pack/test/functional/services/ml/common_ui.ts | 2 +- .../services/ml/data_frame_analytics_results.ts | 2 +- .../services/ml/data_frame_analytics_table.ts | 2 +- .../services/ml/stack_management_jobs.ts | 2 +- x-pack/test/functional/services/ml/swim_lane.ts | 2 +- .../services/ml/trained_models_table.ts | 2 +- .../services/observability/alerts/common.ts | 2 +- .../test/functional/services/search_sessions.ts | 2 +- .../services/transform/transform_table.ts | 2 +- .../page_objects/app_search.ts | 2 +- .../page_objects/triggers_actions_ui_page.ts | 5 +---- .../test_suites/resolver/index.ts | 2 +- .../apps/integrations/endpoint_exceptions.ts | 2 +- .../page_objects/endpoint_page.ts | 2 +- ...ingest_manager_create_package_policy_page.ts | 2 +- .../page_objects/page_utils.ts | 2 +- .../page_objects/detections/index.ts | 2 +- .../page_objects/hosts/index.ts | 2 +- x-pack/test/tsconfig.json | 1 + .../upgrade/services/rules_upgrade_services.ts | 5 +---- .../page_objects/svl_common_navigation.ts | 2 +- .../svl_triggers_actions_ui_page.ts | 5 +---- .../common/discover/x_pack/visualize_field.ts | 2 +- .../common/examples/search/warnings.ts | 2 +- .../index_management/component_templates.ts | 2 +- .../index_management/index_templates.ts | 2 +- .../observability/infra/hosts_page.ts | 2 +- x-pack/test_serverless/tsconfig.json | 1 + 98 files changed, 119 insertions(+), 107 deletions(-) rename {test/functional/services/common => packages/kbn-ftr-common-functional-ui-services/services}/find.ts (98%) rename {test/functional => packages/kbn-ftr-common-functional-ui-services}/services/remote/__tests__/fixtures/several_nested_window_size_changes/config.js (100%) rename {test/functional => packages/kbn-ftr-common-functional-ui-services}/services/remote/__tests__/fixtures/several_nested_window_size_changes/test.js (100%) rename {test/functional => packages/kbn-ftr-common-functional-ui-services}/services/remote/__tests__/fixtures/several_nested_window_size_changes/test2.js (100%) rename {test/functional => packages/kbn-ftr-common-functional-ui-services}/services/remote/__tests__/fixtures/several_nested_window_size_changes/test3.1.js (100%) rename {test/functional => packages/kbn-ftr-common-functional-ui-services}/services/remote/__tests__/fixtures/several_nested_window_size_changes/test3.js (100%) rename {test/functional => packages/kbn-ftr-common-functional-ui-services}/services/remote/__tests__/remote_default_window_size.js (89%) rename {test/functional => packages/kbn-ftr-common-functional-ui-services}/services/remote/browsers.ts (100%) rename {test/functional => packages/kbn-ftr-common-functional-ui-services}/services/remote/create_stdout_stream.ts (100%) rename {test/functional => packages/kbn-ftr-common-functional-ui-services}/services/remote/index.ts (74%) rename {test/functional => packages/kbn-ftr-common-functional-ui-services}/services/remote/network_profiles.ts (100%) rename {test/functional => packages/kbn-ftr-common-functional-ui-services}/services/remote/poll_for_log_entry.ts (100%) rename {test/functional => packages/kbn-ftr-common-functional-ui-services}/services/remote/prevent_parallel_calls.test.js (100%) rename {test/functional => packages/kbn-ftr-common-functional-ui-services}/services/remote/prevent_parallel_calls.ts (100%) rename {test/functional => packages/kbn-ftr-common-functional-ui-services}/services/remote/remote.ts (98%) rename {test/functional => packages/kbn-ftr-common-functional-ui-services}/services/remote/webdriver.ts (100%) rename {test/functional/services/lib => packages/kbn-ftr-common-functional-ui-services/services}/web_element_wrapper/custom_cheerio_api.ts (100%) rename {test/functional/services/lib => packages/kbn-ftr-common-functional-ui-services/services}/web_element_wrapper/index.ts (100%) rename {test/functional/services/lib => packages/kbn-ftr-common-functional-ui-services/services}/web_element_wrapper/scroll_into_view_if_necessary.js (97%) rename {test/functional/services/lib => packages/kbn-ftr-common-functional-ui-services/services}/web_element_wrapper/web_element_wrapper.ts (99%) rename {test/functional/services/common => packages/kbn-ftr-common-functional-ui-services}/types.ts (100%) diff --git a/.eslintrc.js b/.eslintrc.js index 56fe621c99bb4..96016911e40aa 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -671,7 +671,7 @@ module.exports = { */ { files: [ - 'test/functional/services/lib/web_element_wrapper/scroll_into_view_if_necessary.js', + 'packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/scroll_into_view_if_necessary.js', '**/browser_exec_scripts/**/*.js', ], rules: { diff --git a/packages/kbn-ftr-common-functional-ui-services/index.ts b/packages/kbn-ftr-common-functional-ui-services/index.ts index 5fe8ae6fd0164..e975c838a54a4 100644 --- a/packages/kbn-ftr-common-functional-ui-services/index.ts +++ b/packages/kbn-ftr-common-functional-ui-services/index.ts @@ -8,3 +8,15 @@ export { services as commonFunctionalUIServices } from './services/all'; export type { FtrProviderContext } from './services/ftr_provider_context'; +export { WebElementWrapper } from './services/web_element_wrapper'; +export type { + CustomCheerio, + CustomCheerioStatic, +} from './services/web_element_wrapper/custom_cheerio_api'; +export { Browsers } from './services/remote/browsers'; +export { + NETWORK_PROFILES, + type NetworkOptions, + type NetworkProfile, +} from './services/remote/network_profiles'; +export type { TimeoutOpt } from './types'; diff --git a/packages/kbn-ftr-common-functional-ui-services/services/all.ts b/packages/kbn-ftr-common-functional-ui-services/services/all.ts index 8c8a723660117..a27655fc867eb 100644 --- a/packages/kbn-ftr-common-functional-ui-services/services/all.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/all.ts @@ -7,7 +7,11 @@ */ import { RetryOnStaleProvider } from './retry_on_stale'; +import { RemoteProvider } from './remote'; +import { FindProvider } from './find'; export const services = { retryOnStale: RetryOnStaleProvider, + __webdriver__: RemoteProvider, + find: FindProvider, }; diff --git a/test/functional/services/common/find.ts b/packages/kbn-ftr-common-functional-ui-services/services/find.ts similarity index 98% rename from test/functional/services/common/find.ts rename to packages/kbn-ftr-common-functional-ui-services/services/find.ts index 682c79047a725..2f8ba340c40be 100644 --- a/test/functional/services/common/find.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/find.ts @@ -8,10 +8,12 @@ import { WebDriver, WebElement, By, until } from 'selenium-webdriver'; -import { Browsers } from '../remote/browsers'; -import { FtrService, FtrProviderContext } from '../../ftr_provider_context'; -import { WebElementWrapper } from '../lib/web_element_wrapper'; -import { TimeoutOpt } from './types'; +import { Browsers } from './remote/browsers'; +import type { FtrProviderContext } from './ftr_provider_context'; +import { WebElementWrapper } from './web_element_wrapper'; +import { TimeoutOpt } from '../types'; + +import { FtrService } from './ftr_provider_context'; export class FindService extends FtrService { private readonly log = this.ctx.getService('log'); diff --git a/packages/kbn-ftr-common-functional-ui-services/services/ftr_provider_context.ts b/packages/kbn-ftr-common-functional-ui-services/services/ftr_provider_context.ts index 979658fbd8edd..bf80085dd4590 100644 --- a/packages/kbn-ftr-common-functional-ui-services/services/ftr_provider_context.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/ftr_provider_context.ts @@ -7,8 +7,13 @@ */ import { GenericFtrProviderContext, GenericFtrService } from '@kbn/test'; +import { RetryService } from '@kbn/ftr-common-functional-services'; +import { services as commonFunctionalUiServices } from './all'; -import type { services } from './all'; +const services = { + ...commonFunctionalUiServices, + retry: RetryService, +}; type Services = typeof services; diff --git a/test/functional/services/remote/__tests__/fixtures/several_nested_window_size_changes/config.js b/packages/kbn-ftr-common-functional-ui-services/services/remote/__tests__/fixtures/several_nested_window_size_changes/config.js similarity index 100% rename from test/functional/services/remote/__tests__/fixtures/several_nested_window_size_changes/config.js rename to packages/kbn-ftr-common-functional-ui-services/services/remote/__tests__/fixtures/several_nested_window_size_changes/config.js diff --git a/test/functional/services/remote/__tests__/fixtures/several_nested_window_size_changes/test.js b/packages/kbn-ftr-common-functional-ui-services/services/remote/__tests__/fixtures/several_nested_window_size_changes/test.js similarity index 100% rename from test/functional/services/remote/__tests__/fixtures/several_nested_window_size_changes/test.js rename to packages/kbn-ftr-common-functional-ui-services/services/remote/__tests__/fixtures/several_nested_window_size_changes/test.js diff --git a/test/functional/services/remote/__tests__/fixtures/several_nested_window_size_changes/test2.js b/packages/kbn-ftr-common-functional-ui-services/services/remote/__tests__/fixtures/several_nested_window_size_changes/test2.js similarity index 100% rename from test/functional/services/remote/__tests__/fixtures/several_nested_window_size_changes/test2.js rename to packages/kbn-ftr-common-functional-ui-services/services/remote/__tests__/fixtures/several_nested_window_size_changes/test2.js diff --git a/test/functional/services/remote/__tests__/fixtures/several_nested_window_size_changes/test3.1.js b/packages/kbn-ftr-common-functional-ui-services/services/remote/__tests__/fixtures/several_nested_window_size_changes/test3.1.js similarity index 100% rename from test/functional/services/remote/__tests__/fixtures/several_nested_window_size_changes/test3.1.js rename to packages/kbn-ftr-common-functional-ui-services/services/remote/__tests__/fixtures/several_nested_window_size_changes/test3.1.js diff --git a/test/functional/services/remote/__tests__/fixtures/several_nested_window_size_changes/test3.js b/packages/kbn-ftr-common-functional-ui-services/services/remote/__tests__/fixtures/several_nested_window_size_changes/test3.js similarity index 100% rename from test/functional/services/remote/__tests__/fixtures/several_nested_window_size_changes/test3.js rename to packages/kbn-ftr-common-functional-ui-services/services/remote/__tests__/fixtures/several_nested_window_size_changes/test3.js diff --git a/test/functional/services/remote/__tests__/remote_default_window_size.js b/packages/kbn-ftr-common-functional-ui-services/services/remote/__tests__/remote_default_window_size.js similarity index 89% rename from test/functional/services/remote/__tests__/remote_default_window_size.js rename to packages/kbn-ftr-common-functional-ui-services/services/remote/__tests__/remote_default_window_size.js index 48210ea209da6..8d5182c457331 100644 --- a/test/functional/services/remote/__tests__/remote_default_window_size.js +++ b/packages/kbn-ftr-common-functional-ui-services/services/remote/__tests__/remote_default_window_size.js @@ -9,9 +9,12 @@ import { fork } from 'child_process'; import expect from '@kbn/expect'; +import { REPO_ROOT } from '@kbn/repo-info'; -const FTR_SCRIPT = require.resolve('../../../../../scripts/functional_test_runner'); -const CONFIG_PATH = require.resolve('./fixtures/several_nested_window_size_changes/config.js'); +const FTR_SCRIPT = require.resolve(`${REPO_ROOT}/scripts/functional_test_runner`); +const CONFIG_PATH = require.resolve( + `${REPO_ROOT}/packages/kbn-ftr-common-functional-ui-services/services/remote/__tests__/fixtures/several_nested_window_size_changes/config.js` +); const SECOND = 1000; const DEFAULT_SIZE = { width: 1600, height: 1000 }; diff --git a/test/functional/services/remote/browsers.ts b/packages/kbn-ftr-common-functional-ui-services/services/remote/browsers.ts similarity index 100% rename from test/functional/services/remote/browsers.ts rename to packages/kbn-ftr-common-functional-ui-services/services/remote/browsers.ts diff --git a/test/functional/services/remote/create_stdout_stream.ts b/packages/kbn-ftr-common-functional-ui-services/services/remote/create_stdout_stream.ts similarity index 100% rename from test/functional/services/remote/create_stdout_stream.ts rename to packages/kbn-ftr-common-functional-ui-services/services/remote/create_stdout_stream.ts diff --git a/test/functional/services/remote/index.ts b/packages/kbn-ftr-common-functional-ui-services/services/remote/index.ts similarity index 74% rename from test/functional/services/remote/index.ts rename to packages/kbn-ftr-common-functional-ui-services/services/remote/index.ts index 452a714c887f1..a85a13948ccc3 100644 --- a/test/functional/services/remote/index.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/remote/index.ts @@ -7,3 +7,5 @@ */ export { RemoteProvider } from './remote'; +export { Browsers } from './browsers'; +export { NETWORK_PROFILES, type NetworkOptions, type NetworkProfile } from './network_profiles'; diff --git a/test/functional/services/remote/network_profiles.ts b/packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts similarity index 100% rename from test/functional/services/remote/network_profiles.ts rename to packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts diff --git a/test/functional/services/remote/poll_for_log_entry.ts b/packages/kbn-ftr-common-functional-ui-services/services/remote/poll_for_log_entry.ts similarity index 100% rename from test/functional/services/remote/poll_for_log_entry.ts rename to packages/kbn-ftr-common-functional-ui-services/services/remote/poll_for_log_entry.ts diff --git a/test/functional/services/remote/prevent_parallel_calls.test.js b/packages/kbn-ftr-common-functional-ui-services/services/remote/prevent_parallel_calls.test.js similarity index 100% rename from test/functional/services/remote/prevent_parallel_calls.test.js rename to packages/kbn-ftr-common-functional-ui-services/services/remote/prevent_parallel_calls.test.js diff --git a/test/functional/services/remote/prevent_parallel_calls.ts b/packages/kbn-ftr-common-functional-ui-services/services/remote/prevent_parallel_calls.ts similarity index 100% rename from test/functional/services/remote/prevent_parallel_calls.ts rename to packages/kbn-ftr-common-functional-ui-services/services/remote/prevent_parallel_calls.ts diff --git a/test/functional/services/remote/remote.ts b/packages/kbn-ftr-common-functional-ui-services/services/remote/remote.ts similarity index 98% rename from test/functional/services/remote/remote.ts rename to packages/kbn-ftr-common-functional-ui-services/services/remote/remote.ts index 6ee7b6e8d9085..6eb10984eeb66 100644 --- a/test/functional/services/remote/remote.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/remote/remote.ts @@ -7,7 +7,7 @@ */ import { NoSuchSessionError, NoSuchWindowError } from 'selenium-webdriver/lib/error'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../ftr_provider_context'; import { initWebDriver, BrowserConfig } from './webdriver'; import { Browsers } from './browsers'; diff --git a/test/functional/services/remote/webdriver.ts b/packages/kbn-ftr-common-functional-ui-services/services/remote/webdriver.ts similarity index 100% rename from test/functional/services/remote/webdriver.ts rename to packages/kbn-ftr-common-functional-ui-services/services/remote/webdriver.ts diff --git a/test/functional/services/lib/web_element_wrapper/custom_cheerio_api.ts b/packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts similarity index 100% rename from test/functional/services/lib/web_element_wrapper/custom_cheerio_api.ts rename to packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts diff --git a/test/functional/services/lib/web_element_wrapper/index.ts b/packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/index.ts similarity index 100% rename from test/functional/services/lib/web_element_wrapper/index.ts rename to packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/index.ts diff --git a/test/functional/services/lib/web_element_wrapper/scroll_into_view_if_necessary.js b/packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/scroll_into_view_if_necessary.js similarity index 97% rename from test/functional/services/lib/web_element_wrapper/scroll_into_view_if_necessary.js rename to packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/scroll_into_view_if_necessary.js index 514d1bb1d9d7b..bc3453bffa7a6 100644 --- a/test/functional/services/lib/web_element_wrapper/scroll_into_view_if_necessary.js +++ b/packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/scroll_into_view_if_necessary.js @@ -1,4 +1,4 @@ -/* eslint-disable @kbn/eslint/require-license-header */ +/* eslint-disable @kbn/eslint/require-license-header, no-var */ /* @notice * Based on the scroll-into-view-if-necessary module from npm diff --git a/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts b/packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts similarity index 99% rename from test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts rename to packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts index 6a914c7273ba3..568d8dc5cd879 100644 --- a/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts @@ -15,7 +15,7 @@ import { ToolingLog } from '@kbn/tooling-log'; import { CustomCheerio, CustomCheerioStatic } from './custom_cheerio_api'; // @ts-ignore not supported yet import { scrollIntoViewIfNecessary } from './scroll_into_view_if_necessary'; -import { Browsers } from '../../remote/browsers'; +import { Browsers } from '../remote/browsers'; interface TypeOptions { charByChar: boolean; diff --git a/packages/kbn-ftr-common-functional-ui-services/tsconfig.json b/packages/kbn-ftr-common-functional-ui-services/tsconfig.json index 0c77cc5d6b917..f8ae6aae1b9be 100644 --- a/packages/kbn-ftr-common-functional-ui-services/tsconfig.json +++ b/packages/kbn-ftr-common-functional-ui-services/tsconfig.json @@ -2,18 +2,15 @@ "extends": "../../tsconfig.base.json", "compilerOptions": { "outDir": "target/types", - "types": [ - "jest", - "node" - ] + "types": ["jest", "cheerio", "node"] }, - "include": [ - "**/*.ts", - ], - "exclude": [ - "target/**/*" - ], + "include": ["**/*.ts"], + "exclude": ["target/**/*"], "kbn_references": [ "@kbn/test", + "@kbn/tooling-log", + "@kbn/repo-info", + "@kbn/test-subj-selector", + "@kbn/ftr-common-functional-services" ] } diff --git a/test/functional/services/common/types.ts b/packages/kbn-ftr-common-functional-ui-services/types.ts similarity index 100% rename from test/functional/services/common/types.ts rename to packages/kbn-ftr-common-functional-ui-services/types.ts diff --git a/test/examples/search/warnings.ts b/test/examples/search/warnings.ts index 3a923b4a2ae60..80d4224d2ef83 100644 --- a/test/examples/search/warnings.ts +++ b/test/examples/search/warnings.ts @@ -9,8 +9,8 @@ import type { estypes } from '@elastic/elasticsearch'; import expect from '@kbn/expect'; import assert from 'assert'; +import type { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import type { FtrProviderContext } from '../../functional/ftr_provider_context'; -import type { WebElementWrapper } from '../../functional/services/lib/web_element_wrapper'; // eslint-disable-next-line import/no-default-export export default function ({ getService, getPageObjects }: FtrProviderContext) { diff --git a/test/functional/apps/discover/group1/_discover_accessibility.ts b/test/functional/apps/discover/group1/_discover_accessibility.ts index f5721f1e03f76..815d5aebe7bbf 100644 --- a/test/functional/apps/discover/group1/_discover_accessibility.ts +++ b/test/functional/apps/discover/group1/_discover_accessibility.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; -import { WebElementWrapper } from '../../../services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { diff --git a/test/functional/apps/kibana_overview/_analytics.ts b/test/functional/apps/kibana_overview/_analytics.ts index 1c4897d5830ac..8fd51106cd239 100644 --- a/test/functional/apps/kibana_overview/_analytics.ts +++ b/test/functional/apps/kibana_overview/_analytics.ts @@ -7,8 +7,8 @@ */ import expect from '@kbn/expect'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { WebElementWrapper } from '../../services/lib/web_element_wrapper'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const find = getService('find'); diff --git a/test/functional/apps/management/data_views/_field_formatter.ts b/test/functional/apps/management/data_views/_field_formatter.ts index 881ba6197510a..fb016151cce5f 100644 --- a/test/functional/apps/management/data_views/_field_formatter.ts +++ b/test/functional/apps/management/data_views/_field_formatter.ts @@ -8,8 +8,8 @@ import { ES_FIELD_TYPES } from '@kbn/field-types'; import expect from '@kbn/expect'; import { FIELD_FORMAT_IDS } from '@kbn/field-formats-plugin/common'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../../ftr_provider_context'; -import { WebElementWrapper } from '../../../services/lib/web_element_wrapper'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); diff --git a/test/functional/page_objects/console_page.ts b/test/functional/page_objects/console_page.ts index 2fabe4222ee4e..51e671d26301b 100644 --- a/test/functional/page_objects/console_page.ts +++ b/test/functional/page_objects/console_page.ts @@ -8,8 +8,8 @@ import { Key } from 'selenium-webdriver'; import { asyncForEach } from '@kbn/std'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../ftr_provider_context'; -import { WebElementWrapper } from '../services/lib/web_element_wrapper'; export class ConsolePageObject extends FtrService { private readonly testSubjects = this.ctx.getService('testSubjects'); diff --git a/test/functional/page_objects/dashboard_page_controls.ts b/test/functional/page_objects/dashboard_page_controls.ts index af6f3f81563d3..f3ca32531995e 100644 --- a/test/functional/page_objects/dashboard_page_controls.ts +++ b/test/functional/page_objects/dashboard_page_controls.ts @@ -17,8 +17,8 @@ import { OptionsListSortingType } from '@kbn/controls-plugin/common/options_list import expect from '@kbn/expect'; import { asyncForEach } from '@kbn/std'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../ftr_provider_context'; -import { WebElementWrapper } from '../services/lib/web_element_wrapper'; interface OptionsListAdditionalSettings { searchTechnique?: OptionsListSearchTechnique; diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts index 9f636fcd8ec78..3ec60eae8e407 100644 --- a/test/functional/page_objects/discover_page.ts +++ b/test/functional/page_objects/discover_page.ts @@ -7,8 +7,8 @@ */ import expect from '@kbn/expect'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../ftr_provider_context'; -import { WebElementWrapper } from '../services/lib/web_element_wrapper'; export class DiscoverPageObject extends FtrService { private readonly retry = this.ctx.getService('retry'); diff --git a/test/functional/page_objects/legacy/data_table_vis.ts b/test/functional/page_objects/legacy/data_table_vis.ts index 122409f28de90..dbc25df9387dd 100644 --- a/test/functional/page_objects/legacy/data_table_vis.ts +++ b/test/functional/page_objects/legacy/data_table_vis.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../../ftr_provider_context'; -import { WebElementWrapper } from '../../services/lib/web_element_wrapper'; export class LegacyDataTableVisPageObject extends FtrService { private readonly testSubjects = this.ctx.getService('testSubjects'); diff --git a/test/functional/page_objects/tag_cloud_page.ts b/test/functional/page_objects/tag_cloud_page.ts index ecd5aad781285..ba7648b323ca9 100644 --- a/test/functional/page_objects/tag_cloud_page.ts +++ b/test/functional/page_objects/tag_cloud_page.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../ftr_provider_context'; -import { WebElementWrapper } from '../services/lib/web_element_wrapper'; export class TagCloudPageObject extends FtrService { private readonly find = this.ctx.getService('find'); diff --git a/test/functional/page_objects/time_picker.ts b/test/functional/page_objects/time_picker.ts index aa8832f28848a..5ea80ce271263 100644 --- a/test/functional/page_objects/time_picker.ts +++ b/test/functional/page_objects/time_picker.ts @@ -7,8 +7,8 @@ */ import moment from 'moment'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../ftr_provider_context'; -import { WebElementWrapper } from '../services/lib/web_element_wrapper'; export type CommonlyUsed = | 'Today' diff --git a/test/functional/page_objects/timelion_page.ts b/test/functional/page_objects/timelion_page.ts index ba1db60bc6350..f7fa16aa416ba 100644 --- a/test/functional/page_objects/timelion_page.ts +++ b/test/functional/page_objects/timelion_page.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ +import type { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../ftr_provider_context'; -import type { WebElementWrapper } from '../services/lib/web_element_wrapper'; export class TimelionPageObject extends FtrService { private readonly testSubjects = this.ctx.getService('testSubjects'); diff --git a/test/functional/page_objects/visual_builder_page.ts b/test/functional/page_objects/visual_builder_page.ts index e20249f362b03..89f1a2e9389c2 100644 --- a/test/functional/page_objects/visual_builder_page.ts +++ b/test/functional/page_objects/visual_builder_page.ts @@ -7,8 +7,8 @@ */ import type { DebugState } from '@elastic/charts'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../ftr_provider_context'; -import { WebElementWrapper } from '../services/lib/web_element_wrapper'; type Duration = | 'Milliseconds' diff --git a/test/functional/services/combo_box.ts b/test/functional/services/combo_box.ts index 4b23dd3bd8b98..69794f3d2a6c8 100644 --- a/test/functional/services/combo_box.ts +++ b/test/functional/services/combo_box.ts @@ -7,8 +7,8 @@ */ import expect from '@kbn/expect'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../ftr_provider_context'; -import { WebElementWrapper } from './lib/web_element_wrapper'; /** * wrapper around EuiComboBox interactions diff --git a/test/functional/services/common/browser.ts b/test/functional/services/common/browser.ts index cac8eec71e7f4..8054816bb4ee3 100644 --- a/test/functional/services/common/browser.ts +++ b/test/functional/services/common/browser.ts @@ -15,14 +15,14 @@ import Url from 'url'; import { NoSuchSessionError } from 'selenium-webdriver/lib/error'; import sharp from 'sharp'; -import { FtrService, type FtrProviderContext } from '../../ftr_provider_context'; -import { WebElementWrapper } from '../lib/web_element_wrapper'; -import { Browsers } from '../remote/browsers'; import { + WebElementWrapper, + Browsers, NETWORK_PROFILES, type NetworkOptions, type NetworkProfile, -} from '../remote/network_profiles'; +} from '@kbn/ftr-common-functional-ui-services'; +import { FtrService, type FtrProviderContext } from '../../ftr_provider_context'; export type Browser = BrowserService; diff --git a/test/functional/services/common/index.ts b/test/functional/services/common/index.ts index b7b8c67a4280d..3d1078d92dc5e 100644 --- a/test/functional/services/common/index.ts +++ b/test/functional/services/common/index.ts @@ -9,7 +9,6 @@ export type { Browser } from './browser'; export { BrowserProvider } from './browser'; export { FailureDebuggingProvider } from './failure_debugging'; -export { FindProvider } from './find'; export { PngService } from './png'; export { ScreenshotsService } from './screenshots'; export { SnapshotsService } from './snapshots'; diff --git a/test/functional/services/common/screenshots.ts b/test/functional/services/common/screenshots.ts index 50421e480dd9c..10b2ccb251610 100644 --- a/test/functional/services/common/screenshots.ts +++ b/test/functional/services/common/screenshots.ts @@ -12,9 +12,9 @@ import { promisify } from 'util'; import del from 'del'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { comparePngs } from '../lib/compare_pngs'; import { FtrProviderContext, FtrService } from '../../ftr_provider_context'; -import { WebElementWrapper } from '../lib/web_element_wrapper'; const mkdirAsync = promisify(mkdir); const writeFileAsync = promisify(writeFile); diff --git a/test/functional/services/common/test_subjects.ts b/test/functional/services/common/test_subjects.ts index b451d3139463b..57d2bbbd64244 100644 --- a/test/functional/services/common/test_subjects.ts +++ b/test/functional/services/common/test_subjects.ts @@ -7,9 +7,8 @@ */ import { subj as testSubjSelector } from '@kbn/test-subj-selector'; -import { WebElementWrapper } from '../lib/web_element_wrapper'; +import { WebElementWrapper, type TimeoutOpt } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../../ftr_provider_context'; -import { TimeoutOpt } from './types'; interface ExistsOptions { timeout?: number; diff --git a/test/functional/services/dashboard/expectations.ts b/test/functional/services/dashboard/expectations.ts index a7993286d80f4..476ffb49f13ee 100644 --- a/test/functional/services/dashboard/expectations.ts +++ b/test/functional/services/dashboard/expectations.ts @@ -7,8 +7,8 @@ */ import expect from '@kbn/expect'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../../ftr_provider_context'; -import { WebElementWrapper } from '../lib/web_element_wrapper'; export class DashboardExpectService extends FtrService { private readonly log = this.ctx.getService('log'); diff --git a/test/functional/services/dashboard/panel_actions.ts b/test/functional/services/dashboard/panel_actions.ts index f07b0bd87177f..14c69eb6b8e2a 100644 --- a/test/functional/services/dashboard/panel_actions.ts +++ b/test/functional/services/dashboard/panel_actions.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { WebElementWrapper } from '../lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../../ftr_provider_context'; const REMOVE_PANEL_DATA_TEST_SUBJ = 'embeddablePanelAction-deletePanel'; diff --git a/test/functional/services/dashboard/panel_drilldown_actions.ts b/test/functional/services/dashboard/panel_drilldown_actions.ts index 222e55950c8be..3a240d58c983d 100644 --- a/test/functional/services/dashboard/panel_drilldown_actions.ts +++ b/test/functional/services/dashboard/panel_drilldown_actions.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { WebElementWrapper } from '../lib/web_element_wrapper'; const CREATE_DRILLDOWN_DATA_TEST_SUBJ = 'embeddablePanelAction-OPEN_FLYOUT_ADD_DRILLDOWN'; const MANAGE_DRILLDOWNS_DATA_TEST_SUBJ = 'embeddablePanelAction-OPEN_FLYOUT_EDIT_DRILLDOWN'; diff --git a/test/functional/services/dashboard/panel_settings.ts b/test/functional/services/dashboard/panel_settings.ts index de75a9c4a7a19..36bd01b1fad0d 100644 --- a/test/functional/services/dashboard/panel_settings.ts +++ b/test/functional/services/dashboard/panel_settings.ts @@ -6,9 +6,9 @@ * Side Public License, v 1. */ +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; import { CommonlyUsed } from '../../page_objects/time_picker'; -import { WebElementWrapper } from '../lib/web_element_wrapper'; export function DashboardCustomizePanelProvider({ getService, getPageObject }: FtrProviderContext) { const log = getService('log'); diff --git a/test/functional/services/data_grid.ts b/test/functional/services/data_grid.ts index df5ba570cfc51..88b95fc8a4ab6 100644 --- a/test/functional/services/data_grid.ts +++ b/test/functional/services/data_grid.ts @@ -8,8 +8,8 @@ import { chunk } from 'lodash'; import { Key } from 'selenium-webdriver'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../ftr_provider_context'; -import { WebElementWrapper } from './lib/web_element_wrapper'; export interface TabbedGridData { columns: string[]; diff --git a/test/functional/services/doc_table.ts b/test/functional/services/doc_table.ts index 685f1748d56b2..9be10301019c0 100644 --- a/test/functional/services/doc_table.ts +++ b/test/functional/services/doc_table.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../ftr_provider_context'; -import { WebElementWrapper } from './lib/web_element_wrapper'; interface SelectOptions { isAnchorRow?: boolean; diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index dc151f1b243e3..de503f8ccf99a 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -13,7 +13,6 @@ import { AppsMenuService } from './apps_menu'; import { BrowserProvider, FailureDebuggingProvider, - FindProvider, PngService, ScreenshotsService, SnapshotsService, @@ -40,7 +39,6 @@ import { InspectorService } from './inspector'; import { FieldEditorService } from './field_editor'; import { ManagementMenuService } from './management'; import { QueryBarService } from './query_bar'; -import { RemoteProvider } from './remote'; import { RenderableService } from './renderable'; import { ToastsService } from './toasts'; import { DataGridService } from './data_grid'; @@ -61,10 +59,8 @@ import { DashboardSettingsProvider } from './dashboard/dashboard_settings'; export const services = { ...commonServiceProviders, ...commonFunctionalUIServices, - __webdriver__: RemoteProvider, filterBar: FilterBarService, queryBar: QueryBarService, - find: FindProvider, testSubjects: TestSubjects, docTable: DocTableService, png: PngService, diff --git a/test/functional/services/saved_objects_finder.ts b/test/functional/services/saved_objects_finder.ts index 12e06fe8a1710..98af7785852d8 100644 --- a/test/functional/services/saved_objects_finder.ts +++ b/test/functional/services/saved_objects_finder.ts @@ -7,8 +7,8 @@ */ import expect from '@kbn/expect'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../ftr_provider_context'; -import { WebElementWrapper } from './lib/web_element_wrapper'; export class SavedObjectsFinderService extends FtrService { private readonly testSubjects = this.ctx.getService('testSubjects'); diff --git a/test/functional/services/visualizations/elastic_chart.ts b/test/functional/services/visualizations/elastic_chart.ts index d87a7a0d3d061..da872eb21670c 100644 --- a/test/functional/services/visualizations/elastic_chart.ts +++ b/test/functional/services/visualizations/elastic_chart.ts @@ -9,8 +9,8 @@ import { DebugState } from '@elastic/charts'; import expect from '@kbn/expect'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../../ftr_provider_context'; -import { WebElementWrapper } from '../lib/web_element_wrapper'; declare global { interface Window { diff --git a/x-pack/test/accessibility/apps/group1/dashboard_panel_options.ts b/x-pack/test/accessibility/apps/group1/dashboard_panel_options.ts index 5f12f3600c29a..a5182a8d2ca03 100644 --- a/x-pack/test/accessibility/apps/group1/dashboard_panel_options.ts +++ b/x-pack/test/accessibility/apps/group1/dashboard_panel_options.ts @@ -5,8 +5,8 @@ * 2.0. */ +import type { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; -import type { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const a11y = getService('a11y'); diff --git a/x-pack/test/functional/apps/discover/visualize_field.ts b/x-pack/test/functional/apps/discover/visualize_field.ts index 428ef13c34866..bbd5e94dc4c75 100644 --- a/x-pack/test/functional/apps/discover/visualize_field.ts +++ b/x-pack/test/functional/apps/discover/visualize_field.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { DebugState } from '@elastic/charts'; -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { diff --git a/x-pack/test/functional/apps/infra/hosts_view.ts b/x-pack/test/functional/apps/infra/hosts_view.ts index f9932421690e0..13657713faac7 100644 --- a/x-pack/test/functional/apps/infra/hosts_view.ts +++ b/x-pack/test/functional/apps/infra/hosts_view.ts @@ -10,7 +10,7 @@ import expect from '@kbn/expect'; import { parse } from 'url'; import { enableInfrastructureHostsView } from '@kbn/observability-plugin/common'; import { ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED } from '@kbn/rule-data-utils'; -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; import { DATES, diff --git a/x-pack/test/functional/apps/observability_log_explorer/dataset_selector.ts b/x-pack/test/functional/apps/observability_log_explorer/dataset_selector.ts index d656301a13891..98cfc79c561ad 100644 --- a/x-pack/test/functional/apps/observability_log_explorer/dataset_selector.ts +++ b/x-pack/test/functional/apps/observability_log_explorer/dataset_selector.ts @@ -5,8 +5,8 @@ * 2.0. */ import expect from '@kbn/expect'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from './config'; -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; const initialPackageMap = { apache: 'Apache HTTP Server', diff --git a/x-pack/test/functional/page_objects/graph_page.ts b/x-pack/test/functional/page_objects/graph_page.ts index 503e8666e0bef..810048a7f144f 100644 --- a/x-pack/test/functional/page_objects/graph_page.ts +++ b/x-pack/test/functional/page_objects/graph_page.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../ftr_provider_context'; interface Node { diff --git a/x-pack/test/functional/page_objects/infra_hosts_view.ts b/x-pack/test/functional/page_objects/infra_hosts_view.ts index 3fbb3d361d879..0c3004acc4fe8 100644 --- a/x-pack/test/functional/page_objects/infra_hosts_view.ts +++ b/x-pack/test/functional/page_objects/infra_hosts_view.ts @@ -6,7 +6,7 @@ */ import { AlertStatus } from '@kbn/rule-data-utils'; -import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../ftr_provider_context'; export function InfraHostsViewProvider({ getService }: FtrProviderContext) { diff --git a/x-pack/test/functional/page_objects/infra_metrics_explorer.ts b/x-pack/test/functional/page_objects/infra_metrics_explorer.ts index e8d9f878b43c5..4e691a164cdb7 100644 --- a/x-pack/test/functional/page_objects/infra_metrics_explorer.ts +++ b/x-pack/test/functional/page_objects/infra_metrics_explorer.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../ftr_provider_context'; export function InfraMetricsExplorerProvider({ getService }: FtrProviderContext) { diff --git a/x-pack/test/functional/page_objects/ingest_pipelines_page.ts b/x-pack/test/functional/page_objects/ingest_pipelines_page.ts index 3e0bc23869bb7..c4800b55aa77c 100644 --- a/x-pack/test/functional/page_objects/ingest_pipelines_page.ts +++ b/x-pack/test/functional/page_objects/ingest_pipelines_page.ts @@ -6,7 +6,7 @@ */ import path from 'path'; -import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../ftr_provider_context'; export function IngestPipelinesPageProvider({ getService, getPageObjects }: FtrProviderContext) { diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index ee9ad1596fbe0..2d3766c137667 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { setTimeout as setTimeoutAsync } from 'timers/promises'; import type { FittingFunction, XYCurveType } from '@kbn/lens-plugin/public'; import { DebugState } from '@elastic/charts'; -import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../ftr_provider_context'; import { logWrapper } from './log_wrapper'; diff --git a/x-pack/test/functional/page_objects/navigational_search.ts b/x-pack/test/functional/page_objects/navigational_search.ts index ae27d6d68a4a5..54c1582f322cc 100644 --- a/x-pack/test/functional/page_objects/navigational_search.ts +++ b/x-pack/test/functional/page_objects/navigational_search.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../ftr_provider_context'; interface SearchResult { diff --git a/x-pack/test/functional/page_objects/observability_log_explorer.ts b/x-pack/test/functional/page_objects/observability_log_explorer.ts index a61682e62a8cb..07cdf818a7ae0 100644 --- a/x-pack/test/functional/page_objects/observability_log_explorer.ts +++ b/x-pack/test/functional/page_objects/observability_log_explorer.ts @@ -11,7 +11,7 @@ import { } from '@kbn/observability-log-explorer-plugin/common'; import rison from '@kbn/rison'; import querystring from 'querystring'; -import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../ftr_provider_context'; export interface IntegrationPackage { diff --git a/x-pack/test/functional/page_objects/tag_management_page.ts b/x-pack/test/functional/page_objects/tag_management_page.ts index 5eb93aa977cf5..30c6689d87b8f 100644 --- a/x-pack/test/functional/page_objects/tag_management_page.ts +++ b/x-pack/test/functional/page_objects/tag_management_page.ts @@ -7,7 +7,7 @@ /* eslint-disable max-classes-per-file */ -import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService, FtrProviderContext } from '../ftr_provider_context'; interface FillTagFormFields { diff --git a/x-pack/test/functional/services/cases/list.ts b/x-pack/test/functional/services/cases/list.ts index 61d588dc261ed..03d1078ccec2c 100644 --- a/x-pack/test/functional/services/cases/list.ts +++ b/x-pack/test/functional/services/cases/list.ts @@ -6,7 +6,7 @@ */ import { CaseSeverity, CaseStatuses } from '@kbn/cases-plugin/common/types/domain'; -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; import { CasesCommon } from './common'; diff --git a/x-pack/test/functional/services/infra_source_configuration_form.ts b/x-pack/test/functional/services/infra_source_configuration_form.ts index 741d42ac16fda..805dfcbbc9dcb 100644 --- a/x-pack/test/functional/services/infra_source_configuration_form.ts +++ b/x-pack/test/functional/services/infra_source_configuration_form.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../ftr_provider_context'; -import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; export function InfraSourceConfigurationFormProvider({ getService, diff --git a/x-pack/test/functional/services/logs_ui/log_entry_categories.ts b/x-pack/test/functional/services/logs_ui/log_entry_categories.ts index 0aec1cbea2210..77098bd918ea6 100644 --- a/x-pack/test/functional/services/logs_ui/log_entry_categories.ts +++ b/x-pack/test/functional/services/logs_ui/log_entry_categories.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; export function LogEntryCategoriesPageProvider({ getPageObjects, getService }: FtrProviderContext) { diff --git a/x-pack/test/functional/services/logs_ui/log_entry_rate.ts b/x-pack/test/functional/services/logs_ui/log_entry_rate.ts index bf58d74a06c44..f8a68f6c924e0 100644 --- a/x-pack/test/functional/services/logs_ui/log_entry_rate.ts +++ b/x-pack/test/functional/services/logs_ui/log_entry_rate.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; export function LogEntryRatePageProvider({ getPageObjects, getService }: FtrProviderContext) { diff --git a/x-pack/test/functional/services/logs_ui/log_stream.ts b/x-pack/test/functional/services/logs_ui/log_stream.ts index 1a068439a2d2d..160e949c84de4 100644 --- a/x-pack/test/functional/services/logs_ui/log_stream.ts +++ b/x-pack/test/functional/services/logs_ui/log_stream.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; import { TabsParams } from '../../page_objects/infra_logs_page'; export function LogStreamPageProvider({ getPageObjects, getService }: FtrProviderContext) { diff --git a/x-pack/test/functional/services/ml/common_table_service.ts b/x-pack/test/functional/services/ml/common_table_service.ts index ac403d62b5ac8..683ac91f4e7a3 100644 --- a/x-pack/test/functional/services/ml/common_table_service.ts +++ b/x-pack/test/functional/services/ml/common_table_service.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; export type MlTableService = ReturnType; diff --git a/x-pack/test/functional/services/ml/common_ui.ts b/x-pack/test/functional/services/ml/common_ui.ts index dc4836ed6f34c..63a1fdf17cf4f 100644 --- a/x-pack/test/functional/services/ml/common_ui.ts +++ b/x-pack/test/functional/services/ml/common_ui.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { ProvidedType } from '@kbn/test'; -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; import type { CanvasElementColorStats } from '../canvas_element'; diff --git a/x-pack/test/functional/services/ml/data_frame_analytics_results.ts b/x-pack/test/functional/services/ml/data_frame_analytics_results.ts index 0fc99e1e032a1..17a409a082ce7 100644 --- a/x-pack/test/functional/services/ml/data_frame_analytics_results.ts +++ b/x-pack/test/functional/services/ml/data_frame_analytics_results.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; import type { CanvasElementColorStats } from '../canvas_element'; import type { MlCommonUI } from './common_ui'; diff --git a/x-pack/test/functional/services/ml/data_frame_analytics_table.ts b/x-pack/test/functional/services/ml/data_frame_analytics_table.ts index 2b89364644a36..c85e38cd78b8e 100644 --- a/x-pack/test/functional/services/ml/data_frame_analytics_table.ts +++ b/x-pack/test/functional/services/ml/data_frame_analytics_table.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import { ProvidedType } from '@kbn/test'; -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; type ExpectedSectionTableEntries = Record; diff --git a/x-pack/test/functional/services/ml/stack_management_jobs.ts b/x-pack/test/functional/services/ml/stack_management_jobs.ts index f8db28deb5092..52b8e005ac94c 100644 --- a/x-pack/test/functional/services/ml/stack_management_jobs.ts +++ b/x-pack/test/functional/services/ml/stack_management_jobs.ts @@ -14,7 +14,7 @@ import path from 'path'; import type { JobType, MlSavedObjectType } from '@kbn/ml-plugin/common/types/saved_objects'; import type { Job, Datafeed } from '@kbn/ml-plugin/common/types/anomaly_detection_jobs'; import type { DataFrameAnalyticsConfig } from '@kbn/ml-data-frame-analytics-utils'; -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import type { FtrProviderContext } from '../../ftr_provider_context'; type SyncFlyoutObjectType = diff --git a/x-pack/test/functional/services/ml/swim_lane.ts b/x-pack/test/functional/services/ml/swim_lane.ts index 54895918a6d0d..d9ad1dd44d98a 100644 --- a/x-pack/test/functional/services/ml/swim_lane.ts +++ b/x-pack/test/functional/services/ml/swim_lane.ts @@ -9,8 +9,8 @@ import expect from '@kbn/expect'; import { ProvidedType } from '@kbn/test'; import { DebugState } from '@elastic/charts'; import { DebugStateAxis } from '@elastic/charts/dist/state/types'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; type HeatmapDebugState = Required>; diff --git a/x-pack/test/functional/services/ml/trained_models_table.ts b/x-pack/test/functional/services/ml/trained_models_table.ts index a186c531703be..4ea56286de4fd 100644 --- a/x-pack/test/functional/services/ml/trained_models_table.ts +++ b/x-pack/test/functional/services/ml/trained_models_table.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { ProvidedType } from '@kbn/test'; import { upperFirst } from 'lodash'; -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import type { FtrProviderContext } from '../../ftr_provider_context'; import type { MlCommonUI } from './common_ui'; import { MappedInputParams, MappedOutput, ModelType, TrainedModelsActions } from './trained_models'; diff --git a/x-pack/test/functional/services/observability/alerts/common.ts b/x-pack/test/functional/services/observability/alerts/common.ts index 57403ef8c3ab3..617fadcf25e28 100644 --- a/x-pack/test/functional/services/observability/alerts/common.ts +++ b/x-pack/test/functional/services/observability/alerts/common.ts @@ -8,8 +8,8 @@ import expect from '@kbn/expect'; import { chunk } from 'lodash'; import { ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED, AlertStatus } from '@kbn/rule-data-utils'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../../ftr_provider_context'; -import { WebElementWrapper } from '../../../../../../test/functional/services/lib/web_element_wrapper'; // Based on the x-pack/test/functional/es_archives/observability/alerts archive. const DATE_WITH_DATA = { diff --git a/x-pack/test/functional/services/search_sessions.ts b/x-pack/test/functional/services/search_sessions.ts index a22e635742686..cd0b60d321279 100644 --- a/x-pack/test/functional/services/search_sessions.ts +++ b/x-pack/test/functional/services/search_sessions.ts @@ -9,7 +9,7 @@ import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { INITIAL_SEARCH_SESSION_REST_VERSION } from '@kbn/data-plugin/server'; import expect from '@kbn/expect'; import { SavedObjectsFindResponse } from '@kbn/core/server'; -import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../ftr_provider_context'; const SEARCH_SESSION_INDICATOR_TEST_SUBJ = 'searchSessionIndicator'; diff --git a/x-pack/test/functional/services/transform/transform_table.ts b/x-pack/test/functional/services/transform/transform_table.ts index 665b04b058106..7a5f303ba155b 100644 --- a/x-pack/test/functional/services/transform/transform_table.ts +++ b/x-pack/test/functional/services/transform/transform_table.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; diff --git a/x-pack/test/functional_enterprise_search/page_objects/app_search.ts b/x-pack/test/functional_enterprise_search/page_objects/app_search.ts index 8c02cdb705272..75fe3da03ed1e 100644 --- a/x-pack/test/functional_enterprise_search/page_objects/app_search.ts +++ b/x-pack/test/functional_enterprise_search/page_objects/app_search.ts @@ -5,9 +5,9 @@ * 2.0. */ +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../ftr_provider_context'; import { TestSubjects } from '../../../../test/functional/services/common'; -import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; export function AppSearchPageProvider({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common']); diff --git a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts index f72677bff7f05..cdffa758420c0 100644 --- a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts +++ b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts @@ -6,10 +6,7 @@ */ import expect from '@kbn/expect'; -import { - CustomCheerio, - CustomCheerioStatic, -} from '../../../../test/functional/services/lib/web_element_wrapper/custom_cheerio_api'; +import type { CustomCheerio, CustomCheerioStatic } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../ftr_provider_context'; const ENTER_KEY = '\uE007'; diff --git a/x-pack/test/plugin_functional/test_suites/resolver/index.ts b/x-pack/test/plugin_functional/test_suites/resolver/index.ts index edc5d25971077..51fa158672623 100644 --- a/x-pack/test/plugin_functional/test_suites/resolver/index.ts +++ b/x-pack/test/plugin_functional/test_suites/resolver/index.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { panAnimationDuration } from '@kbn/security-solution-plugin/public/resolver/store/camera/scaling_constants'; -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; diff --git a/x-pack/test/security_solution_endpoint/apps/integrations/endpoint_exceptions.ts b/x-pack/test/security_solution_endpoint/apps/integrations/endpoint_exceptions.ts index 539101c795047..8647d418a6395 100644 --- a/x-pack/test/security_solution_endpoint/apps/integrations/endpoint_exceptions.ts +++ b/x-pack/test/security_solution_endpoint/apps/integrations/endpoint_exceptions.ts @@ -11,7 +11,7 @@ import { IndexedHostsAndAlertsResponse } from '@kbn/security-solution-plugin/com import { EXCEPTION_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import { ArtifactElasticsearchProperties } from '@kbn/fleet-plugin/server/services'; import { FoundExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; import { targetTags } from '../../target_tags'; diff --git a/x-pack/test/security_solution_endpoint/page_objects/endpoint_page.ts b/x-pack/test/security_solution_endpoint/page_objects/endpoint_page.ts index ec3eaf97eb81b..ceea71593a95e 100644 --- a/x-pack/test/security_solution_endpoint/page_objects/endpoint_page.ts +++ b/x-pack/test/security_solution_endpoint/page_objects/endpoint_page.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../ftr_provider_context'; export function EndpointPageProvider({ getService, getPageObjects }: FtrProviderContext) { diff --git a/x-pack/test/security_solution_endpoint/page_objects/ingest_manager_create_package_policy_page.ts b/x-pack/test/security_solution_endpoint/page_objects/ingest_manager_create_package_policy_page.ts index 913d1e18d1dc7..acdb58460cbbd 100644 --- a/x-pack/test/security_solution_endpoint/page_objects/ingest_manager_create_package_policy_page.ts +++ b/x-pack/test/security_solution_endpoint/page_objects/ingest_manager_create_package_policy_page.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../ftr_provider_context'; -import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; export function IngestManagerCreatePackagePolicy({ getService, diff --git a/x-pack/test/security_solution_endpoint/page_objects/page_utils.ts b/x-pack/test/security_solution_endpoint/page_objects/page_utils.ts index 69cb8e455b152..d14846f8583ed 100644 --- a/x-pack/test/security_solution_endpoint/page_objects/page_utils.ts +++ b/x-pack/test/security_solution_endpoint/page_objects/page_utils.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../ftr_provider_context'; -import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; export function EndpointPageUtils({ getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); diff --git a/x-pack/test/security_solution_ftr/page_objects/detections/index.ts b/x-pack/test/security_solution_ftr/page_objects/detections/index.ts index a8ff43a8e06bf..e45fa7f7a5eb7 100644 --- a/x-pack/test/security_solution_ftr/page_objects/detections/index.ts +++ b/x-pack/test/security_solution_ftr/page_objects/detections/index.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../../../functional/ftr_provider_context'; -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; const ALERT_TABLE_ROW_CSS_SELECTOR = '[data-test-subj="alertsTable"] .euiDataGridRow'; diff --git a/x-pack/test/security_solution_ftr/page_objects/hosts/index.ts b/x-pack/test/security_solution_ftr/page_objects/hosts/index.ts index 0d80db3141214..50e232a8693e1 100644 --- a/x-pack/test/security_solution_ftr/page_objects/hosts/index.ts +++ b/x-pack/test/security_solution_ftr/page_objects/hosts/index.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../../../functional/ftr_provider_context'; -import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; export class HostsPageObject extends FtrService { private readonly pageObjects = this.ctx.getPageObjects(['common', 'header']); diff --git a/x-pack/test/tsconfig.json b/x-pack/test/tsconfig.json index 894d4c8039946..4ca836a475546 100644 --- a/x-pack/test/tsconfig.json +++ b/x-pack/test/tsconfig.json @@ -165,5 +165,6 @@ "@kbn/log-explorer-plugin", "@kbn/security-plugin-types-common", "@kbn/typed-react-router-config", + "@kbn/ftr-common-functional-ui-services", ] } diff --git a/x-pack/test/upgrade/services/rules_upgrade_services.ts b/x-pack/test/upgrade/services/rules_upgrade_services.ts index 188f41bcddc9d..54780fbe5adfb 100644 --- a/x-pack/test/upgrade/services/rules_upgrade_services.ts +++ b/x-pack/test/upgrade/services/rules_upgrade_services.ts @@ -6,11 +6,8 @@ */ import expect from '@kbn/expect'; +import type { CustomCheerio, CustomCheerioStatic } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../ftr_provider_context'; -import { - CustomCheerio, - CustomCheerioStatic, -} from '../../../../test/functional/services/lib/web_element_wrapper/custom_cheerio_api'; export function RulesHelper({ getPageObjects, getService }: FtrProviderContext) { const find = getService('find'); diff --git a/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts b/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts index 93b5dea4f0495..9a91f5da1240d 100644 --- a/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts +++ b/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts @@ -16,8 +16,8 @@ import type { NavigationID as DevNavId } from '@kbn/default-nav-devtools'; // use this for nicer type suggestions, but allow any string anyway type NavigationId = MlNavId | AlNavId | MgmtNavId | DevNavId | string; +import type { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import type { FtrProviderContext } from '../ftr_provider_context'; -import type { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; const getSectionIdTestSubj = (sectionId: NavigationId) => `~nav-item-${sectionId}`; diff --git a/x-pack/test_serverless/functional/page_objects/svl_triggers_actions_ui_page.ts b/x-pack/test_serverless/functional/page_objects/svl_triggers_actions_ui_page.ts index 589544cca9c5e..e9f407c06753f 100644 --- a/x-pack/test_serverless/functional/page_objects/svl_triggers_actions_ui_page.ts +++ b/x-pack/test_serverless/functional/page_objects/svl_triggers_actions_ui_page.ts @@ -6,10 +6,7 @@ */ import expect from '@kbn/expect'; -import type { - CustomCheerio, - CustomCheerioStatic, -} from '../../../../test/functional/services/lib/web_element_wrapper/custom_cheerio_api'; +import type { CustomCheerio, CustomCheerioStatic } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../ftr_provider_context'; const ENTER_KEY = '\uE007'; diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/visualize_field.ts b/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/visualize_field.ts index ab1ad279b886b..e412fea58df57 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/visualize_field.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/visualize_field.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import type { WebElementWrapper } from '../../../../../../../test/functional/services/lib/web_element_wrapper'; +import type { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { diff --git a/x-pack/test_serverless/functional/test_suites/common/examples/search/warnings.ts b/x-pack/test_serverless/functional/test_suites/common/examples/search/warnings.ts index a254cb753c864..43ec250ff9967 100644 --- a/x-pack/test_serverless/functional/test_suites/common/examples/search/warnings.ts +++ b/x-pack/test_serverless/functional/test_suites/common/examples/search/warnings.ts @@ -8,7 +8,7 @@ import type { estypes } from '@elastic/elasticsearch'; import expect from '@kbn/expect'; import assert from 'assert'; -import type { WebElementWrapper } from '../../../../../../../test/functional/services/lib/web_element_wrapper'; +import type { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import type { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { diff --git a/x-pack/test_serverless/functional/test_suites/common/management/index_management/component_templates.ts b/x-pack/test_serverless/functional/test_suites/common/management/index_management/component_templates.ts index 9e044667692cf..e70470582b2b5 100644 --- a/x-pack/test_serverless/functional/test_suites/common/management/index_management/component_templates.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management/index_management/component_templates.ts @@ -7,8 +7,8 @@ import expect from '@kbn/expect'; +import type { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../../../ftr_provider_context'; -import type { WebElementWrapper } from '../../../../../../../test/functional/services/lib/web_element_wrapper'; export default ({ getPageObjects, getService }: FtrProviderContext) => { const pageObjects = getPageObjects(['svlCommonPage', 'common', 'indexManagement', 'header']); diff --git a/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_templates.ts b/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_templates.ts index 791d3c313b7ab..371ee4debe98f 100644 --- a/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_templates.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_templates.ts @@ -7,8 +7,8 @@ import expect from '@kbn/expect'; +import type { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../../../ftr_provider_context'; -import type { WebElementWrapper } from '../../../../../../../test/functional/services/lib/web_element_wrapper'; export default ({ getPageObjects, getService }: FtrProviderContext) => { const pageObjects = getPageObjects(['svlCommonPage', 'common', 'indexManagement', 'header']); diff --git a/x-pack/test_serverless/functional/test_suites/observability/infra/hosts_page.ts b/x-pack/test_serverless/functional/test_suites/observability/infra/hosts_page.ts index 7e23b43b253c7..92dfb107dd440 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/infra/hosts_page.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/infra/hosts_page.ts @@ -7,7 +7,7 @@ import moment from 'moment'; import expect from '@kbn/expect'; -import type { WebElementWrapper } from '../../../../../../test/functional/services/lib/web_element_wrapper'; +import type { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import type { FtrProviderContext } from '../../../ftr_provider_context'; import { HOSTS_VIEW_PATH } from './constants'; diff --git a/x-pack/test_serverless/tsconfig.json b/x-pack/test_serverless/tsconfig.json index 54c1e26f069d1..c9c37a3c3f3a1 100644 --- a/x-pack/test_serverless/tsconfig.json +++ b/x-pack/test_serverless/tsconfig.json @@ -84,5 +84,6 @@ "@kbn/log-explorer-plugin", "@kbn/index-management-plugin", "@kbn/alerting-plugin", + "@kbn/ftr-common-functional-ui-services", ] } From 49886a5d79308c6367a108140c5ddea1dbaf3df6 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Thu, 4 Jan 2024 12:30:53 -0600 Subject: [PATCH 024/100] skip failing test suite (#174194, #174195) --- .../actions/assignees/edit_assignees_flyout.test.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/public/components/actions/assignees/edit_assignees_flyout.test.tsx b/x-pack/plugins/cases/public/components/actions/assignees/edit_assignees_flyout.test.tsx index d6f65ff09b694..9001faa12a2a6 100644 --- a/x-pack/plugins/cases/public/components/actions/assignees/edit_assignees_flyout.test.tsx +++ b/x-pack/plugins/cases/public/components/actions/assignees/edit_assignees_flyout.test.tsx @@ -16,7 +16,9 @@ import { waitFor } from '@testing-library/react'; jest.mock('../../../containers/user_profiles/api'); -describe('EditAssigneesFlyout', () => { +// Failing: See https://github.com/elastic/kibana/issues/174194 +// Failing: See https://github.com/elastic/kibana/issues/174195 +describe.skip('EditAssigneesFlyout', () => { let appMock: AppMockRenderer; /** From 33f83681326ab05db53fcaafef382631201868a7 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 4 Jan 2024 13:33:32 -0500 Subject: [PATCH 025/100] skip failing test suite (#174204) --- .../routes/csp_benchmark_rules_bulk_update.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_bulk_update.ts b/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_bulk_update.ts index 022ab5e3b32ff..2c7d0ce250b02 100644 --- a/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_bulk_update.ts +++ b/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_bulk_update.ts @@ -93,7 +93,8 @@ export default function ({ getService }: FtrProviderContext) { log.debug('CSP plugin is initialized'); }); - describe('Verify update csp rules states API', async () => { + // Failing: See https://github.com/elastic/kibana/issues/174204 + describe.skip('Verify update csp rules states API', async () => { before(async () => { await waitForPluginInitialized(); }); From 6d909fff999da629e7886a0683c78a1ebf9e254b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yulia=20=C4=8Cech?= <6585477+yuliacech@users.noreply.github.com> Date: Thu, 4 Jan 2024 19:58:09 +0100 Subject: [PATCH 026/100] [Index Management] Fix managed data streams badge (#173408) ## Summary This PR fixes the badge "managed" missing from the data streams list. The code used to check that the data stream has both conditions for a managed data streams `meta.managed: true` and `meta.managed_by: 'ingest-manager'`. The check for `ingest-manager` is not coorect since it's been renamed to fleet. Instead of updating the check though, I decided to only leave the condition for `meta.managed : true` and I removed all mentions of "Fleet" from the Data streams tab. I believe that is more consistent for the UI, since we don't mention "Fleet-managed" anywhere else like ILM, index templates etc. ### Screenshot Screenshot 2023-12-18 at 16 11 35 --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../home/data_streams_tab.test.ts | 24 ++++--------------- .../public/application/lib/data_streams.tsx | 9 ++++--- .../data_stream_list/data_stream_badges.tsx | 6 ++--- .../data_stream_list/data_stream_list.tsx | 6 ++--- .../translations/translations/fr-FR.json | 2 -- .../translations/translations/ja-JP.json | 2 -- .../translations/translations/zh-CN.json | 2 -- .../data_streams_tab/data_streams_tab.ts | 6 ++--- .../page_objects/index_management_page.ts | 8 ++----- .../test_suites/common/management/index.ts | 6 +---- .../index_management/data_streams.ts | 6 ++--- .../management/index_management/index.ts | 19 +++++++++++++++ 12 files changed, 43 insertions(+), 53 deletions(-) create mode 100644 x-pack/test_serverless/functional/test_suites/common/management/index_management/index.ts diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.test.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.test.ts index db38796d2ab3b..e306398c541c7 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.test.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.test.ts @@ -71,7 +71,7 @@ describe('Data Streams tab', () => { expect(exists('emptyPrompt')).toBe(true); }); - test('when Ingest Manager is disabled, goes to index templates tab when "Get started" link is clicked', async () => { + test('when Fleet is disabled, goes to index templates tab when "Get started" link is clicked', async () => { testBed = await setup(httpSetup, { plugins: {}, url: urlServiceMock, @@ -796,7 +796,7 @@ describe('Data Streams tab', () => { _meta: { package: 'test', managed: true, - managed_by: 'ingest-manager', + managed_by: 'fleet', }, }); const nonManagedDataStream = createDataStreamPayload({ name: 'non-managed-data-stream' }); @@ -813,19 +813,12 @@ describe('Data Streams tab', () => { testBed.component.update(); }); - test('listed in the table with Fleet-managed label', () => { + test('listed in the table with managed label', () => { const { table } = testBed; const { tableCellsValues } = table.getMetaData('dataStreamTable'); expect(tableCellsValues).toEqual([ - [ - '', - `managed-data-stream${nonBreakingSpace}Fleet-managed`, - 'green', - '1', - '7 days', - 'Delete', - ], + ['', `managed-data-stream${nonBreakingSpace}Managed`, 'green', '1', '7 days', 'Delete'], ['', 'non-managed-data-stream', 'green', '1', '7 days', 'Delete'], ]); }); @@ -835,14 +828,7 @@ describe('Data Streams tab', () => { let { tableCellsValues } = table.getMetaData('dataStreamTable'); expect(tableCellsValues).toEqual([ - [ - '', - `managed-data-stream${nonBreakingSpace}Fleet-managed`, - 'green', - '1', - '7 days', - 'Delete', - ], + ['', `managed-data-stream${nonBreakingSpace}Managed`, 'green', '1', '7 days', 'Delete'], ['', 'non-managed-data-stream', 'green', '1', '7 days', 'Delete'], ]); diff --git a/x-pack/plugins/index_management/public/application/lib/data_streams.tsx b/x-pack/plugins/index_management/public/application/lib/data_streams.tsx index c16b28f73410a..44852c5dc3230 100644 --- a/x-pack/plugins/index_management/public/application/lib/data_streams.tsx +++ b/x-pack/plugins/index_management/public/application/lib/data_streams.tsx @@ -12,9 +12,8 @@ import { EuiIcon, EuiToolTip } from '@elastic/eui'; import { splitSizeAndUnits, DataStream } from '../../../common'; import { timeUnits, extraTimeUnits } from '../constants/time_units'; -export const isFleetManaged = (dataStream: DataStream): boolean => { - // TODO check if the wording will change to 'fleet' - return Boolean(dataStream._meta?.managed && dataStream._meta?.managed_by === 'ingest-manager'); +export const isManaged = (dataStream: DataStream): boolean => { + return Boolean(dataStream._meta?.managed); }; export const filterDataStreams = ( @@ -23,13 +22,13 @@ export const filterDataStreams = ( ): DataStream[] => { return dataStreams.filter((dataStream: DataStream) => { // include all data streams that are neither hidden nor managed - if (!dataStream.hidden && !isFleetManaged(dataStream)) { + if (!dataStream.hidden && !isManaged(dataStream)) { return true; } if (dataStream.hidden && visibleTypes.includes('hidden')) { return true; } - return isFleetManaged(dataStream) && visibleTypes.includes('managed'); + return isManaged(dataStream) && visibleTypes.includes('managed'); }); }; diff --git a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_badges.tsx b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_badges.tsx index 39c6f61e75dde..2f98b6ac357a4 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_badges.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_badges.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { EuiBadge, EuiBadgeGroup } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { DataStream } from '../../../../../common'; -import { isFleetManaged } from '../../../lib/data_streams'; +import { isManaged } from '../../../lib/data_streams'; interface Props { dataStream: DataStream; @@ -17,12 +17,12 @@ interface Props { export const DataStreamsBadges: React.FunctionComponent = ({ dataStream }) => { const badges = []; - if (isFleetManaged(dataStream)) { + if (isManaged(dataStream)) { badges.push( ); diff --git a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx index fa4efa61bf548..125f676897ffb 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx @@ -84,7 +84,7 @@ export const DataStreamList: React.FunctionComponent>({ managed: { name: i18n.translate('xpack.idxMgmt.dataStreamList.viewManagedLabel', { - defaultMessage: 'Fleet-managed data streams', + defaultMessage: 'Managed data streams', }), checked: 'on', }, @@ -226,7 +226,7 @@ export const DataStreamList: React.FunctionComponent {i18n.translate( - 'xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsCtaIngestManagerLink', + 'xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsCtaFleetLink', { defaultMessage: 'Fleet', } diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index cbbd515a86e1b..e7fa92aa02a3c 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -18390,7 +18390,6 @@ "xpack.idxMgmt.createIndex.successfullyCreatedIndexMessage": "Création réussie de l'index : {indexName}", "xpack.idxMgmt.dataStreamList.dataStreamsDescription": "Les flux de données conservent des données de séries temporelles sur plusieurs index. {learnMoreLink}", "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsCtaIndexTemplateMessage": "Lancez-vous avec les flux de données en créant un {link}.", - "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsCtaIngestManagerMessage": "Lancez-vous avec les flux de données dans {link}.", "xpack.idxMgmt.dataStreamList.table.deleteDataStreamsButtonLabel": "Supprimer {count, plural, one {le flux de données} many {flux de données} other {flux de données}}", "xpack.idxMgmt.deleteDataStreamsConfirmationModal.confirmButtonLabel": "Supprimer {dataStreamsCount, plural, one {le flux de données} many {flux de données} other {flux de données}}", "xpack.idxMgmt.deleteDataStreamsConfirmationModal.deleteDescription": "Vous êtes sur le point de supprimer {dataStreamsCount, plural, one {ce flux de données} many {ces flux de données} other {ces flux de données}} :", @@ -18687,7 +18686,6 @@ "xpack.idxMgmt.dataStreamDetailPanel.timestampFieldTitle": "Champ d'horodatage", "xpack.idxMgmt.dataStreamDetailPanel.timestampFieldToolTip": "Champ d'horodatage partagé par tous les documents du flux de données.", "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsCtaIndexTemplateLink": "modèle d'index composable", - "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsCtaIngestManagerLink": "Fleet", "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsDescription": "Les flux de données conservent des données de séries temporelles sur plusieurs index.", "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsTitle": "Vous n'avez pas encore de flux de données", "xpack.idxMgmt.dataStreamList.loadingDataStreamsDescription": "Chargement des flux de données en cours…", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index f0575cc0496fb..4a23239256f53 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -18403,7 +18403,6 @@ "xpack.idxMgmt.createIndex.successfullyCreatedIndexMessage": "インデックスの作成が正常に完了しました:{indexName}", "xpack.idxMgmt.dataStreamList.dataStreamsDescription": "データストリームは複数のインデックスの時系列データを格納します。{learnMoreLink}", "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsCtaIndexTemplateMessage": "{link}を作成して、データストリームを開始します。", - "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsCtaIngestManagerMessage": "{link}でデータストリームを開始します。", "xpack.idxMgmt.dataStreamList.table.deleteDataStreamsButtonLabel": "{count, plural, other {データストリーム}}削除", "xpack.idxMgmt.deleteDataStreamsConfirmationModal.confirmButtonLabel": "{dataStreamsCount, plural, other {データストリーム}}削除", "xpack.idxMgmt.deleteDataStreamsConfirmationModal.deleteDescription": "{dataStreamsCount, plural, other {これらのデータストリーム}}を削除しようとしています:", @@ -18700,7 +18699,6 @@ "xpack.idxMgmt.dataStreamDetailPanel.timestampFieldTitle": "タイムスタンプフィールド", "xpack.idxMgmt.dataStreamDetailPanel.timestampFieldToolTip": "タイムスタンプフィールドはデータストリームのすべてのドキュメントで共有されます。", "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsCtaIndexTemplateLink": "作成可能なインデックステンプレート", - "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsCtaIngestManagerLink": "Fleet", "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsDescription": "データストリームは複数のインデックスの時系列データを格納します。", "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsTitle": "まだデータストリームがありません", "xpack.idxMgmt.dataStreamList.loadingDataStreamsDescription": "データストリームを読み込んでいます…", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 2a5c081a8d014..ccce90db35aaf 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -18470,7 +18470,6 @@ "xpack.idxMgmt.createIndex.successfullyCreatedIndexMessage": "已成功创建索引:{indexName}", "xpack.idxMgmt.dataStreamList.dataStreamsDescription": "数据流在多个索引上存储时序数据。{learnMoreLink}", "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsCtaIndexTemplateMessage": "通过创建 {link} 来开始使用数据流。", - "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsCtaIngestManagerMessage": "开始使用 {link} 中的数据流。", "xpack.idxMgmt.dataStreamList.table.deleteDataStreamsButtonLabel": "删除 {count, plural, other {数据流}}", "xpack.idxMgmt.deleteDataStreamsConfirmationModal.confirmButtonLabel": "删除 {dataStreamsCount, plural, other {数据流}}", "xpack.idxMgmt.deleteDataStreamsConfirmationModal.deleteDescription": "您即将删除{dataStreamsCount, plural, other {以下数据流}}:", @@ -18767,7 +18766,6 @@ "xpack.idxMgmt.dataStreamDetailPanel.timestampFieldTitle": "时间戳字段", "xpack.idxMgmt.dataStreamDetailPanel.timestampFieldToolTip": "时间戳字段由数据流中的所有文档共享。", "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsCtaIndexTemplateLink": "可组合索引模板", - "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsCtaIngestManagerLink": "Fleet", "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsDescription": "数据流存储多个索引的时序数据。", "xpack.idxMgmt.dataStreamList.emptyPrompt.noDataStreamsTitle": "您尚未有任何数据流", "xpack.idxMgmt.dataStreamList.loadingDataStreamsDescription": "正在加载数据流……", diff --git a/x-pack/test/functional/apps/index_management/data_streams_tab/data_streams_tab.ts b/x-pack/test/functional/apps/index_management/data_streams_tab/data_streams_tab.ts index 9d3da94fead4a..4480063da220b 100644 --- a/x-pack/test/functional/apps/index_management/data_streams_tab/data_streams_tab.ts +++ b/x-pack/test/functional/apps/index_management/data_streams_tab/data_streams_tab.ts @@ -78,7 +78,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('shows the details flyout when clicking on a data stream', async () => { // Open details flyout - await pageObjects.indexManagement.clickDataStreamAt(0); + await pageObjects.indexManagement.clickDataStreamNameLink(TEST_DS_NAME); // Verify url is stateful const url = await browser.getCurrentUrl(); expect(url).to.contain(`/data_streams/${TEST_DS_NAME}`); @@ -90,7 +90,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('allows to update data retention', async () => { // Open details flyout - await pageObjects.indexManagement.clickDataStreamAt(0); + await pageObjects.indexManagement.clickDataStreamNameLink(TEST_DS_NAME); // Open the edit retention dialog await testSubjects.click('manageDataStreamButton'); await testSubjects.click('editDataRetentionButton'); @@ -112,7 +112,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('allows to disable data retention', async () => { // Open details flyout - await pageObjects.indexManagement.clickDataStreamAt(0); + await pageObjects.indexManagement.clickDataStreamNameLink(TEST_DS_NAME); // Open the edit retention dialog await testSubjects.click('manageDataStreamButton'); await testSubjects.click('editDataRetentionButton'); diff --git a/x-pack/test/functional/page_objects/index_management_page.ts b/x-pack/test/functional/page_objects/index_management_page.ts index 9dc9d30fd375d..19eb3f2824f3a 100644 --- a/x-pack/test/functional/page_objects/index_management_page.ts +++ b/x-pack/test/functional/page_objects/index_management_page.ts @@ -22,9 +22,6 @@ export function IndexManagementPageProvider({ getService }: FtrProviderContext) async reloadIndicesButton() { return await testSubjects.find('reloadIndicesButton'); }, - async toggleRollupIndices() { - await testSubjects.click('checkboxToggles-rollupToggle'); - }, async toggleHiddenIndices() { await testSubjects.click('indexTableIncludeHiddenIndicesToggle'); }, @@ -34,9 +31,8 @@ export function IndexManagementPageProvider({ getService }: FtrProviderContext) await policyDetailsLinks[indexOfRow].click(); }, - async clickDataStreamAt(indexOfRow: number): Promise { - const dataStreamLinks = await testSubjects.findAll('nameLink'); - await dataStreamLinks[indexOfRow].click(); + async clickDataStreamNameLink(name: string): Promise { + await find.clickByLinkText(name); }, async clickDeleteEnrichPolicyAt(indexOfRow: number): Promise { diff --git a/x-pack/test_serverless/functional/test_suites/common/management/index.ts b/x-pack/test_serverless/functional/test_suites/common/management/index.ts index 3291f50dc6bc8..e523e27c3cf00 100644 --- a/x-pack/test_serverless/functional/test_suites/common/management/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management/index.ts @@ -9,11 +9,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default ({ loadTestFile }: FtrProviderContext) => { describe('Serverless Common UI - Management', function () { - loadTestFile(require.resolve('./index_management/index_templates')); - loadTestFile(require.resolve('./index_management/indices')); - loadTestFile(require.resolve('./index_management/create_enrich_policy')); - loadTestFile(require.resolve('./index_management/enrich_policies')); - loadTestFile(require.resolve('./index_management/component_templates')); + loadTestFile(require.resolve('./index_management')); loadTestFile(require.resolve('./transforms/search_bar_features')); loadTestFile(require.resolve('./transforms/transform_list')); loadTestFile(require.resolve('./advanced_settings')); diff --git a/x-pack/test_serverless/functional/test_suites/common/management/index_management/data_streams.ts b/x-pack/test_serverless/functional/test_suites/common/management/index_management/data_streams.ts index bbf55e359d360..4bd839e2c9ebb 100644 --- a/x-pack/test_serverless/functional/test_suites/common/management/index_management/data_streams.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management/index_management/data_streams.ts @@ -88,7 +88,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('shows the details flyout when clicking on a data stream', async () => { // Open details flyout - await pageObjects.indexManagement.clickDataStreamAt(0); + await pageObjects.indexManagement.clickDataStreamNameLink(TEST_DS_NAME); // Verify url is stateful const url = await browser.getCurrentUrl(); expect(url).to.contain(`/data_streams/${TEST_DS_NAME}`); @@ -100,7 +100,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('allows to update data retention', async () => { // Open details flyout - await pageObjects.indexManagement.clickDataStreamAt(0); + await pageObjects.indexManagement.clickDataStreamNameLink(TEST_DS_NAME); // Open the edit retention dialog await testSubjects.click('manageDataStreamButton'); await testSubjects.click('editDataRetentionButton'); @@ -122,7 +122,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('allows to disable data retention', async () => { // Open details flyout - await pageObjects.indexManagement.clickDataStreamAt(0); + await pageObjects.indexManagement.clickDataStreamNameLink(TEST_DS_NAME); // Open the edit retention dialog await testSubjects.click('manageDataStreamButton'); await testSubjects.click('editDataRetentionButton'); diff --git a/x-pack/test_serverless/functional/test_suites/common/management/index_management/index.ts b/x-pack/test_serverless/functional/test_suites/common/management/index_management/index.ts new file mode 100644 index 0000000000000..0df628a2ba587 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/management/index_management/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default ({ loadTestFile }: FtrProviderContext) => { + describe('Index Management', function () { + loadTestFile(require.resolve('./component_templates')); + loadTestFile(require.resolve('./create_enrich_policy')); + loadTestFile(require.resolve('./data_streams')); + loadTestFile(require.resolve('./enrich_policies')); + loadTestFile(require.resolve('./index_templates')); + loadTestFile(require.resolve('./indices')); + }); +}; From 46a58541fa8ce21f86a32408cbc759c1bf22487b Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 4 Jan 2024 14:51:46 -0500 Subject: [PATCH 027/100] skip failing test suite (#173558) --- .../common/management/data_views/_runtime_fields.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test_serverless/functional/test_suites/common/management/data_views/_runtime_fields.ts b/x-pack/test_serverless/functional/test_suites/common/management/data_views/_runtime_fields.ts index f900329539e69..b7bc99d9aecb1 100644 --- a/x-pack/test_serverless/functional/test_suites/common/management/data_views/_runtime_fields.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management/data_views/_runtime_fields.ts @@ -16,7 +16,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['settings', 'common']); const testSubjects = getService('testSubjects'); - describe('runtime fields', function () { + // Failing: See https://github.com/elastic/kibana/issues/173558 + describe.skip('runtime fields', function () { this.tags(['skipFirefox']); before(async function () { From 133016850fabf44f3f527496a67eab5d102443b4 Mon Sep 17 00:00:00 2001 From: Hannah Mudge Date: Thu, 4 Jan 2024 14:39:44 -0700 Subject: [PATCH 028/100] [Dashboard Usability] Conditionally auto focus on title input in panel settings flyout (#173777) Closes https://github.com/elastic/kibana/issues/170786 ## Summary Currently, in order to change a panel title, the most efficient way to do this (assuming the dashboard is already in edit mode) is to click on the panel title -> click on the title input in the flyout -> click save at the bottom of the flyout. Notice that this process currently takes **three** clicks, which can start to add up if you need to change multiple titles in one session - so, in order to remove one click from this process, I've made it so that the title input is **auto focused** on when opening the settings flyout through the panel title (and not when it is opened from the context menu). > [!NOTE] > I chose to make this auto-focus behaviour conditional on how the flyout was opened because, from an a11y perspective, it can be jarring to have your focus taken out of the natural element order (as noted in the [EUI docs](https://eui.elastic.co/#/layout/popover#setting-an-initial-focus)). It feels natural that, in order to change the panel title, you click on it - so, auto focusing on the title input makes sense, even when using keyboard controls. However, if you are opening the settings flyout via the context menu, it is **less likely** that the goal is to change the title - so, forcing the focus could feel unnatural in this case. I added tests for this new auto focus behaviour and, since I was interested in learning a bit more about RTL, I also added a few other tests for the dashboard panel components. As part of this, I migrated a few functional tests to unit tests, since this is a faster and more reliable way to test certain rendering conditionals. ### Video https://github.com/elastic/kibana/assets/8698078/229c1303-c81d-46b8-a567-76885361d9fa ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] 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 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) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../embeddable_panel/embeddable_panel.tsx | 29 +-- .../can_inherit_time_range.ts | 2 +- .../custom_time_range_badge.test.ts | 31 +-- .../custom_time_range_badge.tsx | 12 +- .../customize_panel_action.test.ts | 15 +- .../customize_panel_action.tsx | 114 +--------- .../customize_panel_editor.test.tsx | 200 ++++++++++++++++++ .../customize_panel_editor.tsx | 55 +++-- .../does_inherit_time_range.ts | 4 +- .../filters_details.tsx | 3 + .../open_customize_panel.tsx | 75 +++++++ .../time_range_helpers.ts | 53 +++++ .../embeddable_panel_header.test.tsx | 171 +++++++++++++++ .../panel_header/embeddable_panel_header.tsx | 4 +- .../panel_header/embeddable_panel_title.tsx | 29 ++- src/plugins/embeddable/public/plugin.tsx | 11 +- src/plugins/embeddable/tsconfig.json | 3 +- .../apps/dashboard/group2/panel_time_range.ts | 15 -- .../apps/dashboard/group2/panel_titles.ts | 38 ---- 19 files changed, 601 insertions(+), 263 deletions(-) create mode 100644 src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_editor.test.tsx create mode 100644 src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/open_customize_panel.tsx create mode 100644 src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/time_range_helpers.ts create mode 100644 src/plugins/embeddable/public/embeddable_panel/panel_header/embeddable_panel_header.test.tsx diff --git a/src/plugins/embeddable/public/embeddable_panel/embeddable_panel.tsx b/src/plugins/embeddable/public/embeddable_panel/embeddable_panel.tsx index c24383ff9fb18..134b65efc9d86 100644 --- a/src/plugins/embeddable/public/embeddable_panel/embeddable_panel.tsx +++ b/src/plugins/embeddable/public/embeddable_panel/embeddable_panel.tsx @@ -6,20 +6,23 @@ * Side Public License, v 1. */ -import { isNil } from 'lodash'; +import { EuiFlexGroup, EuiFlexItem, EuiPanel, htmlIdGenerator } from '@elastic/eui'; import classNames from 'classnames'; -import { distinct, map } from 'rxjs'; +import { isNil } from 'lodash'; import React, { ReactNode, useEffect, useMemo, useState } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiPanel, htmlIdGenerator } from '@elastic/eui'; +import { distinct, map } from 'rxjs'; -import { UI_SETTINGS } from '@kbn/data-plugin/common'; import { PanelLoader } from '@kbn/panel-loader'; +import { core, embeddableStart, inspector } from '../kibana_services'; +import { EmbeddableErrorHandler, EmbeddableOutput, ViewMode } from '../lib'; +import { EmbeddablePanelError } from './embeddable_panel_error'; import { + CustomizePanelAction, EditPanelAction, - RemovePanelAction, InspectPanelAction, - CustomizePanelAction, + RemovePanelAction, } from './panel_actions'; +import { EmbeddablePanelHeader } from './panel_header/embeddable_panel_header'; import { EmbeddablePhase, EmbeddablePhaseEvent, @@ -30,10 +33,6 @@ import { useSelectFromEmbeddableInput, useSelectFromEmbeddableOutput, } from './use_select_from_embeddable'; -import { EmbeddablePanelError } from './embeddable_panel_error'; -import { core, embeddableStart, inspector } from '../kibana_services'; -import { ViewMode, EmbeddableErrorHandler, EmbeddableOutput } from '../lib'; -import { EmbeddablePanelHeader } from './panel_header/embeddable_panel_header'; const getEventStatus = (output: EmbeddableOutput): EmbeddablePhase => { if (!isNil(output.error)) { @@ -61,8 +60,6 @@ export const EmbeddablePanel = (panelProps: UnwrappedEmbeddablePanelProps) => { * bypass the trigger registry. */ const universalActions = useMemo(() => { - const commonlyUsedRanges = core.uiSettings.get(UI_SETTINGS.TIMEPICKER_QUICK_RANGES); - const dateFormat = core.uiSettings.get(UI_SETTINGS.DATE_FORMAT); const stateTransfer = embeddableStart.getStateTransfer(); const editPanel = new EditPanelAction( embeddableStart.getEmbeddableFactory, @@ -71,13 +68,7 @@ export const EmbeddablePanel = (panelProps: UnwrappedEmbeddablePanelProps) => { ); const actions: PanelUniversalActions = { - customizePanel: new CustomizePanelAction( - core.overlays, - core.theme, - editPanel, - commonlyUsedRanges, - dateFormat - ), + customizePanel: new CustomizePanelAction(editPanel), removePanel: new RemovePanelAction(), editPanel, }; diff --git a/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/can_inherit_time_range.ts b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/can_inherit_time_range.ts index 139933c8d9390..f2c1a3b7a9aac 100644 --- a/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/can_inherit_time_range.ts +++ b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/can_inherit_time_range.ts @@ -8,8 +8,8 @@ import type { TimeRange } from '@kbn/es-query'; -import { TimeRangeInput } from './customize_panel_action'; import { Embeddable, IContainer, ContainerInput } from '../../..'; +import { TimeRangeInput } from './time_range_helpers'; interface ContainerTimeRangeInput extends ContainerInput { timeRange: TimeRange; diff --git a/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/custom_time_range_badge.test.ts b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/custom_time_range_badge.test.ts index 454c92a602691..1c1b7226b7f30 100644 --- a/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/custom_time_range_badge.test.ts +++ b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/custom_time_range_badge.test.ts @@ -6,16 +6,13 @@ * Side Public License, v 1. */ -import { themeServiceMock } from '@kbn/core-theme-browser-mocks'; -import { overlayServiceMock } from '@kbn/core-overlays-browser-mocks'; - import { - TimeRangeEmbeddable, TimeRangeContainer, + TimeRangeEmbeddable, TIME_RANGE_EMBEDDABLE, } from '../../../lib/test_samples/embeddables'; -import { CustomTimeRangeBadge } from './custom_time_range_badge'; import { EditPanelAction } from '../edit_panel_action/edit_panel_action'; +import { CustomTimeRangeBadge } from './custom_time_range_badge'; const editPanelAction = { execute: jest.fn(), @@ -42,13 +39,7 @@ test(`badge is not compatible with embeddable that inherits from parent`, async const child = container.getChild('1'); - const compatible = await new CustomTimeRangeBadge( - overlayServiceMock.createStartContract(), - themeServiceMock.createStartContract(), - editPanelAction, - [], - 'MM YYYY' - ).isCompatible({ + const compatible = await new CustomTimeRangeBadge(editPanelAction, 'MM YYYY').isCompatible({ embeddable: child, }); expect(compatible).toBe(false); @@ -76,13 +67,7 @@ test(`badge is compatible with embeddable that has custom time range`, async () const child = container.getChild('1'); - const compatible = await new CustomTimeRangeBadge( - overlayServiceMock.createStartContract(), - themeServiceMock.createStartContract(), - editPanelAction, - [], - 'MM YYYY' - ).isCompatible({ + const compatible = await new CustomTimeRangeBadge(editPanelAction, 'MM YYYY').isCompatible({ embeddable: child, }); expect(compatible).toBe(true); @@ -109,13 +94,7 @@ test('Attempting to execute on incompatible embeddable throws an error', async ( const child = container.getChild('1'); - const badge = await new CustomTimeRangeBadge( - overlayServiceMock.createStartContract(), - themeServiceMock.createStartContract(), - editPanelAction, - [], - 'MM YYYY' - ); + const badge = await new CustomTimeRangeBadge(editPanelAction, 'MM YYYY'); async function check() { await badge.execute({ embeddable: child }); diff --git a/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/custom_time_range_badge.tsx b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/custom_time_range_badge.tsx index 08e864b76b1ab..5866c3b5ec195 100644 --- a/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/custom_time_range_badge.tsx +++ b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/custom_time_range_badge.tsx @@ -11,9 +11,10 @@ import { PrettyDuration } from '@elastic/eui'; import { renderToString } from 'react-dom/server'; import { Action } from '@kbn/ui-actions-plugin/public'; -import { Embeddable } from '../../..'; +import { EditPanelAction, Embeddable } from '../../..'; import { doesInheritTimeRange } from './does_inherit_time_range'; -import { TimeRangeInput, hasTimeRange, CustomizePanelAction } from './customize_panel_action'; +import { CustomizePanelAction } from './customize_panel_action'; +import { hasTimeRange, TimeRangeInput } from './time_range_helpers'; export const CUSTOM_TIME_RANGE_BADGE = 'CUSTOM_TIME_RANGE_BADGE'; @@ -29,6 +30,13 @@ export class CustomTimeRangeBadge public readonly id = CUSTOM_TIME_RANGE_BADGE; public order = 7; + constructor( + protected readonly editPanel: EditPanelAction, + protected readonly dateFormat?: string + ) { + super(editPanel); + } + public getDisplayName({ embeddable }: TimeBadgeActionContext) { return renderToString( { }); test('execute should open flyout', async () => { - const customizePanelAction = new CustomizePanelAction(overlays, theme, editPanelActionMock); - const spy = jest.spyOn(overlays, 'openFlyout'); - await customizePanelAction.execute({ embeddable }); + const customizePanelAction = new CustomizePanelAction(editPanelActionMock); + const spy = jest.spyOn(openCustomizePanel, 'openCustomizePanelFlyout'); + await customizePanelAction.execute({ embeddable }); expect(spy).toHaveBeenCalled(); }); diff --git a/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_action.tsx b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_action.tsx index 63fc1902102b6..7f70ecf51acac 100644 --- a/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_action.tsx +++ b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_action.tsx @@ -6,48 +6,16 @@ * Side Public License, v 1. */ -import React from 'react'; import { i18n } from '@kbn/i18n'; -import { TimeRange } from '@kbn/es-query'; -import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public'; -import { OverlayStart, ThemeServiceStart } from '@kbn/core/public'; -import { toMountPoint } from '@kbn/react-kibana-mount'; import { Action, IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; -import { core } from '../../../kibana_services'; -import { - IEmbeddable, - Embeddable, - EmbeddableInput, - EmbeddableOutput, - EditPanelAction, -} from '../../..'; -import { ViewMode, CommonlyUsedRange } from '../../../lib/types'; -import { tracksOverlays } from '../track_overlays'; -import { CustomizePanelEditor } from './customize_panel_editor'; +import { EditPanelAction, Embeddable, IEmbeddable } from '../../..'; +import { ViewMode } from '../../../lib/types'; +import { openCustomizePanelFlyout } from './open_customize_panel'; +import { isTimeRangeCompatible, TimeRangeInput } from './time_range_helpers'; export const ACTION_CUSTOMIZE_PANEL = 'ACTION_CUSTOMIZE_PANEL'; -const VISUALIZE_EMBEDDABLE_TYPE = 'visualization'; - -type VisualizeEmbeddable = IEmbeddable<{ id: string }, EmbeddableOutput & { visTypeName: string }>; - -function isVisualizeEmbeddable( - embeddable: IEmbeddable | VisualizeEmbeddable -): embeddable is VisualizeEmbeddable { - return embeddable.type === VISUALIZE_EMBEDDABLE_TYPE; -} - -export interface TimeRangeInput extends EmbeddableInput { - timeRange: TimeRange; -} - -export function hasTimeRange( - embeddable: IEmbeddable | Embeddable -): embeddable is Embeddable { - return (embeddable as Embeddable).getInput().timeRange !== undefined; -} - export interface CustomizePanelActionContext { embeddable: IEmbeddable | Embeddable; } @@ -57,35 +25,7 @@ export class CustomizePanelAction implements Action public id = ACTION_CUSTOMIZE_PANEL; public order = 40; - constructor( - protected readonly overlays: OverlayStart, - protected readonly theme: ThemeServiceStart, - protected readonly editPanel: EditPanelAction, - protected readonly commonlyUsedRanges?: CommonlyUsedRange[], - protected readonly dateFormat?: string - ) {} - - protected isTimeRangeCompatible({ embeddable }: CustomizePanelActionContext): boolean { - const isInputControl = - isVisualizeEmbeddable(embeddable) && - (embeddable as VisualizeEmbeddable).getOutput().visTypeName === 'input_control_vis'; - - const isMarkdown = - isVisualizeEmbeddable(embeddable) && - (embeddable as VisualizeEmbeddable).getOutput().visTypeName === 'markdown'; - - const isImage = embeddable.type === 'image'; - const isNavigation = embeddable.type === 'navigation'; - - return Boolean( - embeddable && - hasTimeRange(embeddable) && - !isInputControl && - !isMarkdown && - !isImage && - !isNavigation - ); - } + constructor(protected readonly editPanel: EditPanelAction) {} public getDisplayName({ embeddable }: CustomizePanelActionContext): string { return i18n.translate('embeddableApi.customizePanel.action.displayName', { @@ -100,7 +40,7 @@ export class CustomizePanelAction implements Action public async isCompatible({ embeddable }: CustomizePanelActionContext) { // It should be possible to customize just the time range in View mode return ( - embeddable.getInput().viewMode === ViewMode.EDIT || this.isTimeRangeCompatible({ embeddable }) + embeddable.getInput().viewMode === ViewMode.EDIT || isTimeRangeCompatible({ embeddable }) ); } @@ -109,46 +49,6 @@ export class CustomizePanelAction implements Action if (!isCompatible) { throw new IncompatibleActionError(); } - - // send the overlay ref to the root embeddable if it is capable of tracking overlays - const rootEmbeddable = embeddable.getRoot(); - const overlayTracker = tracksOverlays(rootEmbeddable) ? rootEmbeddable : undefined; - - const { Provider: KibanaReactContextProvider } = createKibanaReactContext({ - uiSettings: core.uiSettings, - }); - - const onEdit = () => { - this.editPanel.execute({ embeddable }); - }; - - const handle = this.overlays.openFlyout( - toMountPoint( - - { - if (overlayTracker) overlayTracker.clearOverlays(); - handle.close(); - }} - onEdit={onEdit} - /> - , - { theme: this.theme, i18n: core.i18n } - ), - { - size: 's', - 'data-test-subj': 'customizePanel', - onClose: (overlayRef) => { - if (overlayTracker) overlayTracker.clearOverlays(); - overlayRef.close(); - }, - maxWidth: true, - } - ); - overlayTracker?.openOverlay(handle); + openCustomizePanelFlyout({ editPanel: this.editPanel, embeddable }); } } diff --git a/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_editor.test.tsx b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_editor.test.tsx new file mode 100644 index 0000000000000..a2ccf9782deba --- /dev/null +++ b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_editor.test.tsx @@ -0,0 +1,200 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; + +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; +import '@testing-library/jest-dom'; +import { render, screen, waitFor } from '@testing-library/react'; + +import { Filter } from '@kbn/es-query'; +import { ViewMode } from '../../../../common'; +import { FilterableEmbeddable, IEmbeddable } from '../../../lib'; +import { + ContactCardEmbeddable, + ContactCardEmbeddableFactory, + ContactCardEmbeddableInput, +} from '../../../lib/test_samples'; +import { EditPanelAction } from '../edit_panel_action/edit_panel_action'; +import { CustomizePanelAction } from './customize_panel_action'; +import { CustomizePanelEditor } from './customize_panel_editor'; + +const editPanelActionMock = { execute: jest.fn() } as unknown as EditPanelAction; + +const mockEmbeddableFactory = new ContactCardEmbeddableFactory((() => null) as any, {} as any); +const customizePanelAction = new CustomizePanelAction(editPanelActionMock); +customizePanelAction.execute = jest.fn(); + +const DEFAULT_PANEL_TITLE = 'Panel title'; + +const createEmbeddable = async ( + initialInput?: Partial +): Promise => { + return await mockEmbeddableFactory.create({ + id: '20', + firstName: 'Bilbo', + lastName: 'Baggins', + title: DEFAULT_PANEL_TITLE, + ...initialInput, + }); +}; + +const DEFAULT_PROPS = { + timeRangeCompatible: true, + onClose: jest.fn(), + onEdit: jest.fn(), +}; + +describe('panel title / description', () => { + test('does not render if in view mode', async () => { + const mockEmbeddable = await createEmbeddable({ viewMode: ViewMode.VIEW }); + render( + + + + ); + + const customizePanelForm = await screen.findByTestId('customizePanelForm'); + const titleDescriptionComponent = screen.queryByTestId('customEmbeddableTitleComponent'); + expect(customizePanelForm).not.toContainElement(titleDescriptionComponent); + }); + + test('title input receives focus when `focusOnTitle` is `true`', async () => { + const mockEmbeddable = await createEmbeddable({ viewMode: ViewMode.EDIT }); + render( + + + + ); + + const customTitleComponent = await screen.findByTestId('customEmbeddablePanelTitleInput'); + expect(customTitleComponent).toHaveFocus(); + }); + + test('title input does not receive focus when `focusOnTitle` is `false`', async () => { + const mockEmbeddable = await createEmbeddable({ viewMode: ViewMode.EDIT }); + render( + + + + ); + + const customTitleComponent = await screen.findByTestId('customEmbeddablePanelTitleInput'); + expect(customTitleComponent).not.toHaveFocus(); + }); +}); + +describe('custom time picker', () => { + test('renders custom time picker if embeddable supports it', async () => { + const mockEmbeddable = await createEmbeddable({ viewMode: ViewMode.EDIT }); + render( + + + + ); + + const customTimeRangeComponent = await screen.findByTestId('customizePanelTimeRangeDatePicker'); + expect(customTimeRangeComponent).toBeDefined(); + }); + + test('does not render custom time picker if embeddable does not support it', async () => { + const mockEmbeddable = await createEmbeddable({ viewMode: ViewMode.EDIT }); + render( + + + + ); + + const customizePanelForm = await screen.findByTestId('customizePanelForm'); + const customTimeRangeComponent = screen.queryByTestId('customizePanelTimeRangeDatePicker'); + expect(customizePanelForm).not.toContainElement(customTimeRangeComponent); + }); + + test('does not render filters and/or query info if embeddable does not support it', async () => { + const mockEmbeddable = await createEmbeddable({ + viewMode: ViewMode.EDIT, + }); + + render( + + + + ); + + const customizePanelForm = await screen.findByTestId('customizePanelForm'); + const customPanelQuery = screen.queryByTestId('panelCustomQueryRow'); + expect(customizePanelForm).not.toContainElement(customPanelQuery); + const customPanelFilters = screen.queryByTestId('panelCustomFiltersRow'); + expect(customizePanelForm).not.toContainElement(customPanelFilters); + }); + + describe('filterable embeddable', () => { + test('renders custom filters, if provided', async () => { + const mockEmbeddable: FilterableEmbeddable = (await createEmbeddable({ + viewMode: ViewMode.EDIT, + })) as unknown as FilterableEmbeddable; + + mockEmbeddable.getFilters = jest.fn().mockResolvedValue([ + { + meta: {}, + query: {}, + $state: {}, + }, + ] as Filter[]); + mockEmbeddable.getQuery = jest.fn().mockResolvedValue({}); + render( + + + + ); + await waitFor(() => { + expect(screen.getByTestId('euiSkeletonLoadingAriaWrapper')).toBeInTheDocument(); + }); + const customPanelQuery = await screen.findByTestId('panelCustomFiltersRow'); + expect(customPanelQuery).toBeInTheDocument(); + }); + + test('renders a custom query, if provided', async () => { + const mockEmbeddable: FilterableEmbeddable = (await createEmbeddable({ + viewMode: ViewMode.EDIT, + })) as unknown as FilterableEmbeddable; + mockEmbeddable.getFilters = jest.fn().mockResolvedValue([]); + mockEmbeddable.getQuery = jest.fn().mockResolvedValue({ query: 'field : value' }); + render( + + + + ); + await waitFor(() => { + expect(screen.getByTestId('euiSkeletonLoadingAriaWrapper')).toBeInTheDocument(); + }); + const customPanelQuery = await screen.findByTestId('customPanelQuery'); + expect(customPanelQuery).toHaveTextContent('field : value'); + }); + }); +}); diff --git a/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_editor.tsx b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_editor.tsx index be1e7df0c1057..9893e016af08b 100644 --- a/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_editor.tsx +++ b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_editor.tsx @@ -6,40 +6,40 @@ * Side Public License, v 1. */ -import React, { useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { - EuiFormRow, - EuiFieldText, - EuiSwitch, - EuiFlyoutHeader, - EuiTitle, - EuiFlyoutBody, - EuiForm, - EuiTextArea, - EuiFlyoutFooter, - EuiButtonEmpty, EuiButton, + EuiButtonEmpty, + EuiFieldText, EuiFlexGroup, EuiFlexItem, - EuiSuperDatePicker, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiForm, + EuiFormRow, EuiSpacer, + EuiSuperDatePicker, + EuiSwitch, + EuiTextArea, + EuiTitle, } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; import { TimeRange } from '@kbn/es-query'; +import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { TimeRangeInput } from './customize_panel_action'; -import { canInheritTimeRange } from './can_inherit_time_range'; -import { doesInheritTimeRange } from './does_inherit_time_range'; import { - IEmbeddable, - Embeddable, CommonlyUsedRange, - ViewMode, + Embeddable, + IEmbeddable, isFilterableEmbeddable, + ViewMode, } from '../../../lib'; +import { canInheritTimeRange } from './can_inherit_time_range'; +import { doesInheritTimeRange } from './does_inherit_time_range'; import { FiltersDetails } from './filters_details'; +import { TimeRangeInput } from './time_range_helpers'; type PanelSettings = { title?: string; @@ -55,10 +55,11 @@ interface CustomizePanelProps { commonlyUsedRanges?: CommonlyUsedRange[]; onClose: () => void; onEdit: () => void; + focusOnTitle?: boolean; } export const CustomizePanelEditor = (props: CustomizePanelProps) => { - const { onClose, embeddable, dateFormat, timeRangeCompatible, onEdit } = props; + const { onClose, embeddable, dateFormat, timeRangeCompatible, onEdit, focusOnTitle } = props; const editMode = embeddable.getInput().viewMode === ViewMode.EDIT; const [hideTitle, setHideTitle] = useState(embeddable.getInput().hidePanelTitles); const [panelDescription, setPanelDescription] = useState( @@ -75,6 +76,13 @@ export const CustomizePanelEditor = (props: CustomizePanelProps) => { ? (embeddable as Embeddable).getInput().timeRange : undefined ); + const initialFocusRef = useRef(null); + + useEffect(() => { + if (focusOnTitle && initialFocusRef.current) { + initialFocusRef.current.focus(); + } + }, [initialFocusRef, focusOnTitle]); const commonlyUsedRangesForDatePicker = props.commonlyUsedRanges ? props.commonlyUsedRanges.map( @@ -108,7 +116,7 @@ export const CustomizePanelEditor = (props: CustomizePanelProps) => { if (!editMode) return null; return ( - <> +

    { } > { )} /> - +
    ); }; @@ -292,7 +301,7 @@ export const CustomizePanelEditor = (props: CustomizePanelProps) => { - + {renderCustomTitleComponent()} {renderCustomTimeRangeComponent()} {renderFilterDetails()} diff --git a/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/does_inherit_time_range.ts b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/does_inherit_time_range.ts index a14ca031c9fb1..7d21a79ab9425 100644 --- a/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/does_inherit_time_range.ts +++ b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/does_inherit_time_range.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { Embeddable, IContainer, ContainerInput } from '../../../lib'; -import { TimeRangeInput } from './customize_panel_action'; +import { ContainerInput, Embeddable, IContainer } from '../../../lib'; +import { TimeRangeInput } from './time_range_helpers'; export function doesInheritTimeRange(embeddable: Embeddable) { if (!embeddable.parent) { diff --git a/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/filters_details.tsx b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/filters_details.tsx index 2f151285fe488..300ed9253f0b9 100644 --- a/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/filters_details.tsx +++ b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/filters_details.tsx @@ -89,6 +89,7 @@ export function FiltersDetails({ embeddable, editMode, onEdit }: FiltersDetailsP {queryString !== '' && ( 0 && ( ; +}) => { + // send the overlay ref to the root embeddable if it is capable of tracking overlays + const rootEmbeddable = embeddable.getRoot(); + const overlayTracker = tracksOverlays(rootEmbeddable) ? rootEmbeddable : undefined; + + const commonlyUsedRanges = core.uiSettings.get(UI_SETTINGS.TIMEPICKER_QUICK_RANGES); + const dateFormat = core.uiSettings.get(UI_SETTINGS.DATE_FORMAT); + + const { Provider: KibanaReactContextProvider } = createKibanaReactContext({ + uiSettings: core.uiSettings, + }); + + const onEdit = () => { + editPanel.execute({ embeddable }); + }; + + const handle = core.overlays.openFlyout( + toMountPoint( + + { + if (overlayTracker) overlayTracker.clearOverlays(); + handle.close(); + }} + onEdit={onEdit} + /> + , + { theme: core.theme, i18n: core.i18n } + ), + { + size: 's', + 'data-test-subj': 'customizePanel', + onClose: (overlayRef) => { + if (overlayTracker) overlayTracker.clearOverlays(); + overlayRef.close(); + }, + maxWidth: true, + } + ); + overlayTracker?.openOverlay(handle); +}; diff --git a/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/time_range_helpers.ts b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/time_range_helpers.ts new file mode 100644 index 0000000000000..0b74809be8a08 --- /dev/null +++ b/src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/time_range_helpers.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 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 { TimeRange } from '@kbn/es-query'; + +import { Embeddable, EmbeddableInput, EmbeddableOutput, IEmbeddable } from '../../../lib'; + +const VISUALIZE_EMBEDDABLE_TYPE = 'visualization'; + +type VisualizeEmbeddable = IEmbeddable<{ id: string }, EmbeddableOutput & { visTypeName: string }>; + +function isVisualizeEmbeddable( + embeddable: IEmbeddable | VisualizeEmbeddable +): embeddable is VisualizeEmbeddable { + return embeddable.type === VISUALIZE_EMBEDDABLE_TYPE; +} + +export interface TimeRangeInput extends EmbeddableInput { + timeRange: TimeRange; +} + +export function hasTimeRange( + embeddable: IEmbeddable | Embeddable +): embeddable is Embeddable { + return (embeddable as Embeddable).getInput().timeRange !== undefined; +} + +export function isTimeRangeCompatible({ embeddable }: { embeddable: IEmbeddable }): boolean { + const isInputControl = + isVisualizeEmbeddable(embeddable) && + (embeddable as VisualizeEmbeddable).getOutput().visTypeName === 'input_control_vis'; + + const isMarkdown = + isVisualizeEmbeddable(embeddable) && + (embeddable as VisualizeEmbeddable).getOutput().visTypeName === 'markdown'; + + const isImage = embeddable.type === 'image'; + const isNavigation = embeddable.type === 'navigation'; + + return Boolean( + embeddable && + hasTimeRange(embeddable) && + !isInputControl && + !isMarkdown && + !isImage && + !isNavigation + ); +} diff --git a/src/plugins/embeddable/public/embeddable_panel/panel_header/embeddable_panel_header.test.tsx b/src/plugins/embeddable/public/embeddable_panel/panel_header/embeddable_panel_header.test.tsx new file mode 100644 index 0000000000000..770ca76edbc33 --- /dev/null +++ b/src/plugins/embeddable/public/embeddable_panel/panel_header/embeddable_panel_header.test.tsx @@ -0,0 +1,171 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; + +import '@testing-library/jest-dom'; +import { render, screen } from '@testing-library/react'; + +import { applicationServiceMock } from '@kbn/core-application-browser-mocks'; +import userEvent from '@testing-library/user-event'; +import { ViewMode } from '../../../common'; +import { + ContactCardEmbeddable, + ContactCardEmbeddableFactory, + ContactCardEmbeddableInput, +} from '../../lib/test_samples'; +import { EditPanelAction } from '../panel_actions'; +import * as openCustomizePanel from '../panel_actions/customize_panel_action/open_customize_panel'; +import { EmbeddablePanelHeader } from './embeddable_panel_header'; + +const getEmbeddableFactory = jest.fn(); +const application = applicationServiceMock.createStartContract(); + +const editPanelAction = new EditPanelAction(getEmbeddableFactory, application); +const mockEmbeddableFactory = new ContactCardEmbeddableFactory((() => null) as any, {} as any); +editPanelAction.execute = jest.fn(); + +const DEFAULT_PANEL_TITLE = 'Panel title'; + +const createEmbeddable = async ( + initialInput?: Partial +): Promise => { + return await mockEmbeddableFactory.create({ + id: '20', + firstName: 'Bilbo', + lastName: 'Baggins', + title: DEFAULT_PANEL_TITLE, + ...initialInput, + }); +}; + +describe('view mode', () => { + test('renders as expected', async () => { + const mockEmbeddable = await createEmbeddable({ viewMode: ViewMode.VIEW }); + render( + + ); + const titleComponent = await screen.findByTestId('dashboardPanelTitle'); + expect(titleComponent).toHaveTextContent(DEFAULT_PANEL_TITLE); + }); + + test('renders tooltip + icon when description provided', async () => { + const mockEmbeddable = await createEmbeddable({ viewMode: ViewMode.VIEW }); + mockEmbeddable.updateOutput({ description: 'This is a description ' }); + render( + + ); + + expect(await screen.findByTestId('embeddablePanelTooltipAnchor')).toBeInTheDocument(); + expect(await screen.findByTestId('embeddablePanelTitleDescriptionIcon')).toBeInTheDocument(); + }); + + test('blank titles are hidden in view mode', async () => { + const mockEmbeddable = await createEmbeddable({ title: '', viewMode: ViewMode.VIEW }); + render( + + ); + + const header = await screen.findByTestId('embeddablePanelHeading'); + const titleComponent = screen.queryByTestId('dashboardPanelTitle'); + expect(header).not.toContainElement(titleComponent); + }); + + test('hiding an individual panel title hides it in view mode', async () => { + const mockEmbeddable = await createEmbeddable({ + viewMode: ViewMode.VIEW, + hidePanelTitles: true, + }); + render( + + ); + + const header = await screen.findByTestId('embeddablePanelHeading'); + const titleComponent = screen.queryByTestId('dashboardPanelTitle'); + expect(header).not.toContainElement(titleComponent); + }); +}); + +describe('edit mode', () => { + test('renders as expected', async () => { + const mockEmbeddable = await createEmbeddable({ viewMode: ViewMode.EDIT }); + render( + + ); + const titleComponent = await screen.findByTestId('dashboardPanelTitle'); + expect(titleComponent).toHaveTextContent(DEFAULT_PANEL_TITLE); + }); + + test('blank titles render [No title] in edit mode', async () => { + const mockEmbeddable = await createEmbeddable({ title: '', viewMode: ViewMode.EDIT }); + render( + + ); + const titleComponent = await screen.findByTestId('embeddablePanelTitleInner'); + expect(titleComponent).toHaveTextContent('[No Title]'); + }); + + test('hiding an individual panel title renders **only** the context menu button in edit mode', async () => { + const mockEmbeddable = await createEmbeddable({ + viewMode: ViewMode.EDIT, + hidePanelTitles: true, + }); + render( + + ); + const titleComponent = await screen.findByTestId('embeddablePanelHeading-'); + const innerTitleComponent = await screen.findByTestId('embeddablePanelTitleInner'); + expect(innerTitleComponent).toBeEmptyDOMElement(); + const menuComponent = await screen.findByTestId('embeddablePanelToggleMenuIcon'); + expect(titleComponent).toContainElement(menuComponent); + }); + + test('clicking title opens customize panel flyout', async () => { + const mockEmbeddable = await createEmbeddable({ viewMode: ViewMode.EDIT }); + render( + + ); + const titleComponent = await screen.findByTestId('embeddablePanelTitleLink'); + + const spy = jest.spyOn(openCustomizePanel, 'openCustomizePanelFlyout'); + userEvent.click(titleComponent); + expect(spy).toHaveBeenCalled(); + }); +}); diff --git a/src/plugins/embeddable/public/embeddable_panel/panel_header/embeddable_panel_header.tsx b/src/plugins/embeddable/public/embeddable_panel/panel_header/embeddable_panel_header.tsx index ee27bbca0605a..3de27d6ad193c 100644 --- a/src/plugins/embeddable/public/embeddable_panel/panel_header/embeddable_panel_header.tsx +++ b/src/plugins/embeddable/public/embeddable_panel/panel_header/embeddable_panel_header.tsx @@ -85,7 +85,7 @@ export const EmbeddablePanelHeader = ({ if (!showPanelBar) { return ( -
    +
    {embeddablePanelContextMenu} {ariaLabelElement}
    @@ -104,7 +104,7 @@ export const EmbeddablePanelHeader = ({ hideTitle={hideTitle} embeddable={embeddable} description={description} - customizePanelAction={universalActions.customizePanel} + editPanelAction={universalActions.editPanel} /> {showBadges && badgeComponents} diff --git a/src/plugins/embeddable/public/embeddable_panel/panel_header/embeddable_panel_title.tsx b/src/plugins/embeddable/public/embeddable_panel/panel_header/embeddable_panel_title.tsx index 734b420d04052..693215a3084ca 100644 --- a/src/plugins/embeddable/public/embeddable_panel/panel_header/embeddable_panel_title.tsx +++ b/src/plugins/embeddable/public/embeddable_panel/panel_header/embeddable_panel_title.tsx @@ -11,21 +11,22 @@ import React, { useMemo } from 'react'; import { EuiIcon, EuiLink, EuiToolTip } from '@elastic/eui'; import { IEmbeddable, ViewMode } from '../../lib'; -import { CustomizePanelAction } from '../panel_actions'; import { getEditTitleAriaLabel, placeholderTitle } from '../embeddable_panel_strings'; +import { EditPanelAction } from '../panel_actions'; +import { openCustomizePanelFlyout } from '../panel_actions/customize_panel_action/open_customize_panel'; export const EmbeddablePanelTitle = ({ viewMode, hideTitle, embeddable, description, - customizePanelAction, + editPanelAction, }: { hideTitle?: boolean; viewMode?: ViewMode; description?: string; embeddable: IEmbeddable; - customizePanelAction?: CustomizePanelAction; + editPanelAction?: EditPanelAction; }) => { const title = embeddable.getTitle(); @@ -39,32 +40,44 @@ export const EmbeddablePanelTitle = ({ if (viewMode === ViewMode.VIEW) { return {title}; } - if (customizePanelAction) { + if (editPanelAction) { return ( customizePanelAction.execute({ embeddable })} + onClick={() => + openCustomizePanelFlyout({ + editPanel: editPanelAction, + embeddable, + focusOnTitle: true, + }) + } > {title || placeholderTitle} ); } return null; - }, [customizePanelAction, embeddable, title, viewMode, hideTitle]); + }, [editPanelAction, embeddable, title, viewMode, hideTitle]); const titleComponentWithDescription = useMemo(() => { - if (!description) return {titleComponent}; + if (!description) + return ( + + {titleComponent} + + ); return ( - + {titleComponent}{' '} { this.appList = appList; @@ -168,13 +167,7 @@ export class EmbeddablePublicPlugin implements Plugin { - it('should not show custom time picker in flyout', async () => { - await dashboardPanelActions.removePanel(); - await PageObjects.dashboard.waitForRenderComplete(); - await dashboardAddPanel.clickMarkdownQuickButton(); - await PageObjects.visEditor.setMarkdownTxt('I am timeless!'); - await PageObjects.visEditor.clickGo(); - await PageObjects.visualize.saveVisualizationAndReturn(); - await PageObjects.dashboard.clickQuickSave(); - await dashboardPanelActions.customizePanel(); - await dashboardCustomizePanel.expectMissingCustomTimeRange(); - }); - }); }); } diff --git a/x-pack/test/functional/apps/dashboard/group2/panel_titles.ts b/x-pack/test/functional/apps/dashboard/group2/panel_titles.ts index 2c0ac33107fea..4d7950042783a 100644 --- a/x-pack/test/functional/apps/dashboard/group2/panel_titles.ts +++ b/x-pack/test/functional/apps/dashboard/group2/panel_titles.ts @@ -78,44 +78,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(panelTitle).to.equal(EMPTY_TITLE); await PageObjects.dashboard.clearUnsavedChanges(); }); - - it('blank titles are hidden in view mode', async () => { - await PageObjects.dashboard.clickCancelOutOfEditMode(); - - const titleVisibility = (await PageObjects.dashboard.getVisibilityOfPanelTitles())[0]; - expect(titleVisibility).to.be(false); - }); - - it('custom titles are visible in view mode', async () => { - await PageObjects.dashboard.switchToEditMode(); - await dashboardPanelActions.customizePanel(); - await dashboardCustomizePanel.setCustomPanelTitle(CUSTOM_TITLE); - await dashboardCustomizePanel.clickSaveButton(); - await PageObjects.dashboard.clickQuickSave(); - await PageObjects.dashboard.clickCancelOutOfEditMode(); - - const titleVisibility = (await PageObjects.dashboard.getVisibilityOfPanelTitles())[0]; - expect(titleVisibility).to.be(true); - }); - - it('hiding an individual panel title hides it in view mode', async () => { - await PageObjects.dashboard.switchToEditMode(); - await dashboardPanelActions.customizePanel(); - await dashboardCustomizePanel.clickToggleHidePanelTitle(); - await dashboardCustomizePanel.clickSaveButton(); - await PageObjects.dashboard.clickQuickSave(); - await PageObjects.dashboard.clickCancelOutOfEditMode(); - - const titleVisibility = (await PageObjects.dashboard.getVisibilityOfPanelTitles())[0]; - expect(titleVisibility).to.be(false); - - // undo the previous hide panel toggle (i.e. make the panel visible) to keep state consistent - await PageObjects.dashboard.switchToEditMode(); - await dashboardPanelActions.customizePanel(); - await dashboardCustomizePanel.clickToggleHidePanelTitle(); - await dashboardCustomizePanel.clickSaveButton(); - await PageObjects.dashboard.clickQuickSave(); - }); }); describe('by reference', () => { From 4af36fece290263c4fd86f0e06d3e12bdb05f81b Mon Sep 17 00:00:00 2001 From: Xavier Mouligneau Date: Thu, 4 Jan 2024 16:41:30 -0500 Subject: [PATCH 029/100] [SECURITY_SOLUTIONS] Only query security alerts with current user (#174216) ## Summary We just got an [SDH#814](https://github.com/elastic/sdh-security-team/issues/814) that tell us that some feature like `KPIs` and `grouping` are not acting as they should be. @PhilippeOberti is doing an investigation to check which feature has been impacted by this bug. This bug has been introduced in this https://github.com/elastic/kibana/pull/112113 since 8.0.0 I think this simple solution should not impact any features. --- .../signals/query_signals_route.test.ts | 27 ++-- .../routes/signals/query_signals_route.ts | 7 +- .../default_license/alerts/index.ts | 1 + .../default_license/alerts/query_alerts.ts | 153 ++++++++++++++++++ 4 files changed, 176 insertions(+), 12 deletions(-) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/query_alerts.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.test.ts index 7c88d5c9192ee..8ae230d65506b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.test.ts @@ -17,18 +17,23 @@ import { import { requestContextMock, serverMock, requestMock } from '../__mocks__'; import { querySignalsRoute } from './query_signals_route'; import { ruleRegistryMocks } from '@kbn/rule-registry-plugin/server/mocks'; +import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; describe('query for signal', () => { let server: ReturnType; let { context } = requestContextMock.createTools(); - const ruleDataClient = ruleRegistryMocks.createRuleDataClient('.alerts-security.alerts'); + context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(getEmptySignalsResponse()) + ); + const ruleDataClient = ruleRegistryMocks.createRuleDataClient('.alerts-security.alerts-'); beforeEach(() => { server = serverMock.create(); ({ context } = requestContextMock.createTools()); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ruleDataClient.getReader().search.mockResolvedValue(getEmptySignalsResponse() as any); + context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getEmptySignalsResponse() as any + ); querySignalsRoute(server.router, ruleDataClient); }); @@ -41,7 +46,7 @@ describe('query for signal', () => { ); expect(response.status).toEqual(200); - expect(ruleDataClient.getReader().search).toHaveBeenCalledWith( + expect(context.core.elasticsearch.client.asCurrentUser.search).toHaveBeenCalledWith( expect.objectContaining({ body: typicalSignalsQuery(), }) @@ -55,9 +60,9 @@ describe('query for signal', () => { ); expect(response.status).toEqual(200); - expect(ruleDataClient.getReader).toHaveBeenCalledWith( + expect(context.core.elasticsearch.client.asCurrentUser.search).toHaveBeenCalledWith( expect.objectContaining({ - namespace: 'default', + index: '.alerts-security.alerts-default', }) ); }); @@ -69,7 +74,7 @@ describe('query for signal', () => { ); expect(response.status).toEqual(200); - expect(ruleDataClient.getReader().search).toHaveBeenCalledWith( + expect(context.core.elasticsearch.client.asCurrentUser.search).toHaveBeenCalledWith( expect.objectContaining({ body: typicalSignalsQueryAggs(), ignore_unavailable: true }) ); }); @@ -81,7 +86,7 @@ describe('query for signal', () => { ); expect(response.status).toEqual(200); - expect(ruleDataClient.getReader().search).toHaveBeenCalledWith( + expect(context.core.elasticsearch.client.asCurrentUser.search).toHaveBeenCalledWith( expect.objectContaining({ body: { ...typicalSignalsQuery(), @@ -92,7 +97,9 @@ describe('query for signal', () => { }); test('catches error if query throws error', async () => { - ruleDataClient.getReader().search.mockRejectedValue(new Error('Test error')); + context.core.elasticsearch.client.asCurrentUser.search.mockRejectedValue( + new Error('Test error') + ); const response = await server.inject( getSignalsAggsQueryRequest(), requestContextMock.convertContext(context) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts index 673b6c2d85818..3bd52ebdaacda 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts @@ -40,6 +40,8 @@ export const querySignalsRoute = ( }, }, async (context, request, response) => { + const esClient = (await context.core).elasticsearch.client.asCurrentUser; + // eslint-disable-next-line @typescript-eslint/naming-convention const { query, aggs, _source, fields, track_total_hits, size, runtime_mappings, sort } = request.body; @@ -58,10 +60,11 @@ export const querySignalsRoute = ( body: '"value" must have at least 1 children', }); } - try { const spaceId = (await context.securitySolution).getSpaceId(); - const result = await ruleDataClient?.getReader({ namespace: spaceId }).search({ + const indexPattern = ruleDataClient?.indexNameWithNamespace(spaceId); + const result = await esClient.search({ + index: indexPattern, body: { query, // Note: I use a spread operator to please TypeScript with aggs: { ...aggs } diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/index.ts index 85e2e602a8929..81923173bf50c 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/index.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/index.ts @@ -15,5 +15,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./open_close_alerts')); loadTestFile(require.resolve('./set_alert_tags')); loadTestFile(require.resolve('./assignments')); + loadTestFile(require.resolve('./query_alerts')); }); } diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/query_alerts.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/query_alerts.ts new file mode 100644 index 0000000000000..6e8e312f9075a --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/query_alerts.ts @@ -0,0 +1,153 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { DETECTION_ENGINE_QUERY_SIGNALS_URL } from '@kbn/security-solution-plugin/common/constants'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +const roleToAccessSecuritySolution = { + name: 'sec_all_spaces', + privileges: { + elasticsearch: { + indices: [ + { + names: ['.alerts-security.alerts-default'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + siem: ['all'], + }, + spaces: ['*'], + }, + ], + }, +}; +const roleToAccessSecuritySolutionWithDls = { + name: 'sec_all_spaces_with_dls', + privileges: { + elasticsearch: { + indices: [ + { + names: ['.alerts-security.alerts-default'], + privileges: ['read'], + query: + '{"wildcard" : { "kibana.alert.ancestors.index" : { "value": ".ds-kibana_does_not_exist" } } }', + }, + ], + }, + kibana: [ + { + feature: { + siem: ['all'], + }, + spaces: ['*'], + }, + ], + }, +}; +const userAllSec = { + username: 'user_all_sec', + password: 'user_all_sec', + full_name: 'userAllSec', + email: 'userAllSec@elastic.co', + roles: [roleToAccessSecuritySolution.name], +}; +const userAllSecWithDls = { + username: 'user_all_sec_with_dls', + password: 'user_all_sec_with_dls', + full_name: 'userAllSecWithDls', + email: 'userAllSecWithDls@elastic.co', + roles: [roleToAccessSecuritySolutionWithDls.name], +}; + +export default ({ getService }: FtrProviderContext) => { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const esArchiver = getService('esArchiver'); + const security = getService('security'); + + describe('find alert with/without doc level security', () => { + before(async () => { + await security.role.create( + roleToAccessSecuritySolution.name, + roleToAccessSecuritySolution.privileges + ); + await security.role.create( + roleToAccessSecuritySolutionWithDls.name, + roleToAccessSecuritySolutionWithDls.privileges + ); + await security.user.create(userAllSec.username, { + password: userAllSec.password, + roles: userAllSec.roles, + full_name: userAllSec.full_name, + email: userAllSec.email, + }); + await security.user.create(userAllSecWithDls.username, { + password: userAllSecWithDls.password, + roles: userAllSecWithDls.roles, + full_name: userAllSecWithDls.full_name, + email: userAllSecWithDls.email, + }); + + await esArchiver.load( + 'x-pack/test/functional/es_archives/security_solution/alerts/8.8.0_multiple_docs', + { + useCreate: true, + docsOnly: true, + } + ); + }); + + after(async () => { + await security.user.delete(userAllSec.username); + await security.user.delete(userAllSecWithDls.username); + await security.role.delete(roleToAccessSecuritySolution.name); + await security.role.delete(roleToAccessSecuritySolutionWithDls.name); + await esArchiver.unload( + 'x-pack/test/functional/es_archives/security_solution/alerts/8.8.0_multiple_docs' + ); + }); + + it('should return alerts with user who has access to security solution privileges', async () => { + const query = { + query: { + bool: { + should: [{ match_all: {} }], + }, + }, + }; + const { body } = await supertestWithoutAuth + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .auth(userAllSec.username, userAllSec.password) + .set('kbn-xsrf', 'true') + .send(query) + .expect(200); + expect(body.hits.total.value).to.eql(3); + }); + + it('should filter out alerts with user who has access to security solution privileges and document level security', async () => { + const query = { + query: { + bool: { + should: [{ match_all: {} }], + }, + }, + }; + const { body } = await supertestWithoutAuth + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .auth(userAllSecWithDls.username, userAllSecWithDls.password) + .set('kbn-xsrf', 'true') + .send(query) + .expect(200); + expect(body.hits.total.value).to.eql(0); + }); + }); +}; From 1021f65f1cd5ac067953bf24c90f096f6fc18c73 Mon Sep 17 00:00:00 2001 From: Ryland Herrick Date: Thu, 4 Jan 2024 15:42:24 -0600 Subject: [PATCH 030/100] [SecuritySolution][EntityAnalytics] Account for Asset Criticality in Risk Scoring (#172417) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary This PR adds asset criticality to the risk scoring calculation. While previous work was done to add the resources and client to create/read asset criticality documents, this PR builds on those to retrieve relevant criticality records and apply them to the intermediate scores calculated via elasticsearch. __Note that the code in this PR that performs the actual calculation/writing of new risk fields is behind a feature flag.__ ### Performance Since this PR adds new logic to an already tight/important code path, we need to ensure that we haven't changed behavior nor performance. I've captured that as a separate task to be done next: https://github.com/elastic/security-team/issues/8223. ### Compatibility Behaviorally, without the feature flag enabled, scoring will skip the criticality workflow and not write new fields (`criticality_level`, `criticality_modifier`). ~~I still have an outstanding task to validate whether this will be an issue until criticality is enabled, and do some smarter short-circuiting.~~ This task uncovered our need for the above feature flag. The one behavioral change introduced in this PR _not_ behind a feature flag is the normalization of our risk category scores. ### Summary of Changes - Adds an `AssetCriticalityService` which provides the API used by risk scoring to retrieve criticality records - Adds new `search` method to the `AssetCriticalityDataClient`: used to generally retrieve multiple criticality records at once - Adds functions to calculate a (currently hard-coded) modifier from a criticality level, and apply it to the risk score via bayesian update - Moves risk score level calculation into javascript (necessary because we need the level to account for criticality) - Moves some risk level code out of threat hunting code and into the `common/entity_analytics` folder - Tests and comments throughout ### TODO - [x] Add new criticality fields to risk score, address upgrade workflow - [x] Validate that code works without criticality being enabled. - [x] Bump task version to invalidate old tasks from being picked up in customer env Outcome: All three of the above are addressed with: 1. Moving the code responsible for adding new fields behind a feature flag ([71f1158](https://github.com/elastic/kibana/pull/172417/commits/71f115800b9ecca21d1c2e0e9014163f2858ece3)) 2. Addressing the upgrade path in a subsequent issue (https://github.com/elastic/security-team/issues/8012) ## How to Review 1. Enable our asset criticality feature flag: > ``` > xpack.securitySolution.enableExperimental: > - entityAnalyticsAssetCriticalityEnabled > ``` 2. Create asset criticality records (see API documentation, or follow [this test](https://github.com/elastic/kibana/pull/172417/files#diff-43f9f394fb7c8eb0f0ace3f5e75482c56a7233ae7d11d5fdb98a89e6404412c3R276) as a setup guide 3. Enable risk engine 4. Observe that new fields are written to risk scores' `_source`, but not mapped/searchable 5. (optional) Observe that the transform subsequently fails 😢 ### Checklist - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed --------- Co-authored-by: Jared Burgett and Ryland Herrick --- .../common/api/entity_analytics/index.ts | 9 + .../entity_analytics/risk_engine/common.yml | 24 +- .../entity_analytics/risk_engine/index.ts | 1 + .../risk_engine/risk_levels.ts | 30 +++ .../entity_analytics/risk_engine/types.ts | 17 ++ .../security_solution/risk_score/all/index.ts | 15 +- .../public/entity_analytics/common/utils.ts | 9 +- .../asset_criticality_data_client.mock.ts | 1 + .../asset_criticality_data_client.test.ts | 64 ++++++ .../asset_criticality_data_client.ts | 33 ++- .../asset_criticality_service.mock.ts | 17 ++ .../asset_criticality_service.test.ts | 206 ++++++++++++++++++ .../asset_criticality_service.ts | 101 +++++++++ .../{configurations.ts => constants.ts} | 11 + .../asset_criticality/helpers.test.ts | 102 +++++++++ .../asset_criticality/helpers.ts | 88 ++++++++ .../asset_criticality/index.ts | 9 + .../calculate_and_persist_risk_scores.ts | 2 + .../risk_score/calculate_risk_scores.mock.ts | 5 +- .../risk_score/calculate_risk_scores.test.ts | 42 +++- .../risk_score/calculate_risk_scores.ts | 187 +++++++++++----- .../entity_analytics/risk_score/constants.ts | 27 +++ .../risk_engine_data_writer.test.ts | 28 +++ .../risk_score/risk_score_service.mock.ts | 4 + .../risk_score/risk_score_service.ts | 15 +- .../risk_score/risk_weights.ts | 2 +- .../risk_score/routes/calculation.test.ts | 3 +- .../risk_score/routes/calculation.ts | 14 +- .../risk_score/routes/preview.test.ts | 3 +- .../risk_score/routes/preview.ts | 14 +- .../tasks/risk_scoring_task.test.ts | 3 + .../risk_score/tasks/risk_scoring_task.ts | 26 ++- .../server/lib/entity_analytics/types.ts | 1 - .../security_solution/server/plugin.ts | 1 + .../server/request_context_factory.ts | 2 +- .../security_solution/server/routes/index.ts | 4 +- .../plugins/security_solution/server/types.ts | 2 +- .../risk_engine/risk_score_calculation.ts | 79 ++++++- .../risk_engine/risk_score_preview.ts | 114 +++++++--- .../risk_scoring_task/task_execution.ts | 67 +++++- .../utils/asset_criticality.ts | 51 ++++- .../entity_analytics/utils/index.ts | 1 + .../entity_analytics/utils/risk_engine.ts | 14 +- 43 files changed, 1303 insertions(+), 145 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/api/entity_analytics/index.ts create mode 100644 x-pack/plugins/security_solution/common/entity_analytics/risk_engine/risk_levels.ts create mode 100644 x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_service.mock.ts create mode 100644 x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_service.test.ts create mode 100644 x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_service.ts rename x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/{configurations.ts => constants.ts} (67%) create mode 100644 x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.test.ts create mode 100644 x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.ts create mode 100644 x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/index.ts create mode 100644 x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/constants.ts diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/index.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/index.ts new file mode 100644 index 0000000000000..2dbb228a91f83 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './asset_criticality'; +export * from './risk_score'; diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/common.yml b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/common.yml index ea4bd4bd86321..4e73c51b9087f 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/common.yml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/common.yml @@ -1,4 +1,10 @@ openapi: 3.0.0 +info: + title: Risk Engine Common Schema + description: Common schema for Risk Engine APIs + version: 1.0.0 + +paths: { } components: schemas: @@ -103,11 +109,27 @@ components: category_1_score: type: number format: double - description: The contribution of Category 1 to the overall risk score (`calculated_score`). Category 1 contains Detection Engine Alerts. + description: The contribution of Category 1 to the overall risk score (`calculated_score_norm`). Category 1 contains Detection Engine Alerts. category_1_count: type: number format: integer description: The number of risk input documents that contributed to the Category 1 score (`category_1_score`). + category_2_score: + type: number + format: double + description: The contribution of Category 2 to the overall risk score (`calculated_score_norm`). Category 2 contains context from external sources. + category_2_count: + type: number + format: integer + description: The number of risk input documents that contributed to the Category 2 score (`category_2_score`). + criticality_level: + type: string + example: very_important + description: The designated criticality level of the entity. Possible values are `not_important`, `normal`, `important`, and `very_important`. + criticality_modifier: + type: number + format: double + description: The numeric modifier corresponding to the criticality level of the entity, which is used as an input to the risk score calculation. inputs: type: array description: A list of the highest-risk documents contributing to this risk score. Useful for investigative purposes. diff --git a/x-pack/plugins/security_solution/common/entity_analytics/risk_engine/index.ts b/x-pack/plugins/security_solution/common/entity_analytics/risk_engine/index.ts index 3da0d8be4f0be..bb75e496f386b 100644 --- a/x-pack/plugins/security_solution/common/entity_analytics/risk_engine/index.ts +++ b/x-pack/plugins/security_solution/common/entity_analytics/risk_engine/index.ts @@ -9,6 +9,7 @@ export * from './after_keys'; export * from './risk_weights'; export * from './identifier_types'; export * from './range'; +export * from './risk_levels'; export * from './types'; export * from './indices'; export * from './constants'; diff --git a/x-pack/plugins/security_solution/common/entity_analytics/risk_engine/risk_levels.ts b/x-pack/plugins/security_solution/common/entity_analytics/risk_engine/risk_levels.ts new file mode 100644 index 0000000000000..d2e777ad710a4 --- /dev/null +++ b/x-pack/plugins/security_solution/common/entity_analytics/risk_engine/risk_levels.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { RiskLevels } from './types'; + +export const RISK_LEVEL_RANGES = { + [RiskLevels.unknown]: { start: 0, stop: 20 }, + [RiskLevels.low]: { start: 20, stop: 40 }, + [RiskLevels.moderate]: { start: 40, stop: 70 }, + [RiskLevels.high]: { start: 70, stop: 90 }, + [RiskLevels.critical]: { start: 90, stop: 100 }, +}; + +export const getRiskLevel = (riskScore: number): RiskLevels => { + if (riskScore >= RISK_LEVEL_RANGES[RiskLevels.critical].start) { + return RiskLevels.critical; + } else if (riskScore >= RISK_LEVEL_RANGES[RiskLevels.high].start) { + return RiskLevels.high; + } else if (riskScore >= RISK_LEVEL_RANGES[RiskLevels.moderate].start) { + return RiskLevels.moderate; + } else if (riskScore >= RISK_LEVEL_RANGES[RiskLevels.low].start) { + return RiskLevels.low; + } else { + return RiskLevels.unknown; + } +}; diff --git a/x-pack/plugins/security_solution/common/entity_analytics/risk_engine/types.ts b/x-pack/plugins/security_solution/common/entity_analytics/risk_engine/types.ts index deed9767ed2cd..f803ec0ed6711 100644 --- a/x-pack/plugins/security_solution/common/entity_analytics/risk_engine/types.ts +++ b/x-pack/plugins/security_solution/common/entity_analytics/risk_engine/types.ts @@ -38,24 +38,41 @@ export interface SimpleRiskInput { export interface EcsRiskScore { '@timestamp': string; host?: { + name: string; risk: Omit; }; user?: { + name: string; risk: Omit; }; } export type RiskInputs = SimpleRiskInput[]; +/** + * The API response object representing a risk score + */ export interface RiskScore { '@timestamp': string; id_field: string; id_value: string; + criticality_level?: string | undefined; + criticality_modifier?: number | undefined; calculated_level: string; calculated_score: number; calculated_score_norm: number; category_1_score: number; category_1_count: number; + category_2_score?: number; + category_2_count?: number; notes: string[]; inputs: RiskInputs; } + +export enum RiskLevels { + unknown = 'Unknown', + low = 'Low', + moderate = 'Moderate', + high = 'High', + critical = 'Critical', +} diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/all/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/all/index.ts index f33eb664628a1..7810c29fbfbfe 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/all/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/all/index.ts @@ -8,7 +8,10 @@ import type { IEsSearchResponse } from '@kbn/data-plugin/common'; import type { Inspect, Maybe, SortField } from '../../../common'; -import type { RiskInputs } from '../../../../entity_analytics/risk_engine'; +import { + type RiskInputs, + RiskLevels as RiskSeverity, +} from '../../../../entity_analytics/risk_engine'; export interface HostsRiskScoreStrategyResponse extends IEsSearchResponse { inspect?: Maybe; @@ -30,6 +33,8 @@ export interface RiskStats { inputs?: RiskInputs; } +export { RiskSeverity }; + export interface HostRiskScore { '@timestamp': string; host: { @@ -85,14 +90,6 @@ export interface RiskScoreItem { [RiskScoreFields.alertsCount]: Maybe; } -export enum RiskSeverity { - unknown = 'Unknown', - low = 'Low', - moderate = 'Moderate', - high = 'High', - critical = 'Critical', -} - export const isUserRiskScore = (risk: HostRiskScore | UserRiskScore): risk is UserRiskScore => 'user' in risk; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/common/utils.ts b/x-pack/plugins/security_solution/public/entity_analytics/common/utils.ts index f6009c85dbd43..b8735c2e7b6fb 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/common/utils.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/common/utils.ts @@ -8,6 +8,7 @@ import { euiLightVars } from '@kbn/ui-theme'; import { RiskSeverity } from '../../../common/search_strategy'; import { SEVERITY_COLOR } from '../../overview/components/detection_response/utils'; +export { RISK_LEVEL_RANGES as RISK_SCORE_RANGES } from '../../../common/entity_analytics/risk_engine'; export const SEVERITY_UI_SORT_ORDER = [ RiskSeverity.unknown, @@ -25,14 +26,6 @@ export const RISK_SEVERITY_COLOUR: { [k in RiskSeverity]: string } = { [RiskSeverity.critical]: SEVERITY_COLOR.critical, }; -export const RISK_SCORE_RANGES = { - [RiskSeverity.unknown]: { start: 0, stop: 20 }, - [RiskSeverity.low]: { start: 20, stop: 40 }, - [RiskSeverity.moderate]: { start: 40, stop: 70 }, - [RiskSeverity.high]: { start: 70, stop: 90 }, - [RiskSeverity.critical]: { start: 90, stop: 100 }, -}; - type SnakeToCamelCaseString = S extends `${infer T}_${infer U}` ? `${T}${Capitalize>}` : S; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.mock.ts index eaf3e9a3ec22e..6b98e880ea6ab 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.mock.ts @@ -12,6 +12,7 @@ const createAssetCriticalityDataClientMock = () => doesIndexExist: jest.fn(), getStatus: jest.fn(), init: jest.fn(), + search: jest.fn(), } as unknown as jest.Mocked); export const assetCriticalityDataClientMock = { create: createAssetCriticalityDataClientMock }; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.test.ts index c06586516d682..83d197123303a 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.test.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.test.ts @@ -57,4 +57,68 @@ describe('AssetCriticalityDataClient', () => { }); }); }); + + describe('#search()', () => { + let esClientMock: ReturnType< + typeof elasticsearchServiceMock.createScopedClusterClient + >['asInternalUser']; + let loggerMock: ReturnType; + let subject: AssetCriticalityDataClient; + + beforeEach(() => { + esClientMock = elasticsearchServiceMock.createScopedClusterClient().asInternalUser; + loggerMock = loggingSystemMock.createLogger(); + subject = new AssetCriticalityDataClient({ + esClient: esClientMock, + logger: loggerMock, + namespace: 'default', + }); + }); + + it('searches in the asset criticality index', async () => { + subject.search({ query: { match_all: {} } }); + + expect(esClientMock.search).toHaveBeenCalledWith( + expect.objectContaining({ index: '.asset-criticality.asset-criticality-default' }) + ); + }); + + it('requires a query parameter', async () => { + subject.search({ query: { match_all: {} } }); + + expect(esClientMock.search).toHaveBeenCalledWith( + expect.objectContaining({ body: { query: { match_all: {} } } }) + ); + }); + + it('accepts a size parameter', async () => { + subject.search({ query: { match_all: {} }, size: 100 }); + + expect(esClientMock.search).toHaveBeenCalledWith(expect.objectContaining({ size: 100 })); + }); + + it('defaults to the default query size', async () => { + subject.search({ query: { match_all: {} } }); + const defaultSize = 1_000; + + expect(esClientMock.search).toHaveBeenCalledWith( + expect.objectContaining({ size: defaultSize }) + ); + }); + + it('caps the size to the maximum query size', async () => { + subject.search({ query: { match_all: {} }, size: 999999 }); + const maxSize = 100_000; + + expect(esClientMock.search).toHaveBeenCalledWith(expect.objectContaining({ size: maxSize })); + }); + + it('ignores an index_not_found_exception if the criticality index does not exist', async () => { + subject.search({ query: { match_all: {} } }); + + expect(esClientMock.search).toHaveBeenCalledWith( + expect.objectContaining({ ignore_unavailable: true }) + ); + }); + }); }); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.ts index afddfd6893240..3ac20360bcae0 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.ts @@ -4,12 +4,14 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import type { ESFilter } from '@kbn/es-types'; +import type { SearchResponse } from '@elastic/elasticsearch/lib/api/types'; import type { Logger, ElasticsearchClient } from '@kbn/core/server'; import { mappingFromFieldMap } from '@kbn/alerting-plugin/common'; -import type { AssetCriticalityRecord } from '../../../../common/api/entity_analytics/asset_criticality'; +import type { AssetCriticalityRecord } from '../../../../common/api/entity_analytics'; import { createOrUpdateIndex } from '../utils/create_or_update_index'; import { getAssetCriticalityIndex } from '../../../../common/entity_analytics/asset_criticality'; -import { assetCriticalityFieldMap } from './configurations'; +import { assetCriticalityFieldMap } from './constants'; interface AssetCriticalityClientOpts { logger: Logger; @@ -25,7 +27,11 @@ interface AssetCriticalityUpsert { type AssetCriticalityIdParts = Pick; +const MAX_CRITICALITY_RESPONSE_SIZE = 100_000; +const DEFAULT_CRITICALITY_RESPONSE_SIZE = 1_000; + const createId = ({ idField, idValue }: AssetCriticalityIdParts) => `${idField}:${idValue}`; + export class AssetCriticalityDataClient { constructor(private readonly options: AssetCriticalityClientOpts) {} /** @@ -43,6 +49,29 @@ export class AssetCriticalityDataClient { }); } + /** + * + * A general method for searching asset criticality records. + * @param query an ESL query to filter criticality results + * @param size the maximum number of records to return. Cannot exceed {@link MAX_CRITICALITY_RESPONSE_SIZE}. If unspecified, will default to {@link DEFAULT_CRITICALITY_RESPONSE_SIZE}. + * @returns criticality records matching the query + */ + public async search({ + query, + size, + }: { + query: ESFilter; + size?: number; + }): Promise> { + const response = await this.options.esClient.search({ + index: this.getIndex(), + ignore_unavailable: true, + body: { query }, + size: Math.min(size ?? DEFAULT_CRITICALITY_RESPONSE_SIZE, MAX_CRITICALITY_RESPONSE_SIZE), + }); + return response; + } + private getIndex() { return getAssetCriticalityIndex(this.options.namespace); } diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_service.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_service.mock.ts new file mode 100644 index 0000000000000..9de2d8c6bae2c --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_service.mock.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { AssetCriticalityService } from './asset_criticality_service'; + +const buildMockAssetCriticalityService = (): jest.Mocked => ({ + getCriticalitiesByIdentifiers: jest.fn().mockResolvedValue([]), + isEnabled: jest.fn().mockReturnValue(true), +}); + +export const assetCriticalityServiceMock = { + create: buildMockAssetCriticalityService, +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_service.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_service.test.ts new file mode 100644 index 0000000000000..7075aacfcb31d --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_service.test.ts @@ -0,0 +1,206 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SearchHit } from '@elastic/elasticsearch/lib/api/types'; + +import type { ExperimentalFeatures } from '../../../../common'; +import type { AssetCriticalityRecord } from '../../../../common/api/entity_analytics'; +import type { AssetCriticalityDataClient } from './asset_criticality_data_client'; +import { assetCriticalityDataClientMock } from './asset_criticality_data_client.mock'; +import { + type AssetCriticalityService, + assetCriticalityServiceFactory, +} from './asset_criticality_service'; + +const buildMockCriticalityHit = ( + overrides: Partial = {} +): SearchHit => ({ + _id: 'host.name:not-found', + _index: '.asset-criticality-default', + _source: { + '@timestamp': '2021-09-16T15:00:00.000Z', + id_field: 'host.name', + id_value: 'hostname', + criticality_level: 'normal', + ...overrides, + }, +}); + +describe('AssetCriticalityService', () => { + describe('#getCriticalitiesByIdentifiers()', () => { + let baseIdentifier: { id_field: string; id_value: string }; + let mockAssetCriticalityDataClient: AssetCriticalityDataClient; + let service: AssetCriticalityService; + + beforeEach(() => { + mockAssetCriticalityDataClient = assetCriticalityDataClientMock.create(); + baseIdentifier = { id_field: 'host.name', id_value: 'not-found' }; + + (mockAssetCriticalityDataClient.search as jest.Mock).mockResolvedValueOnce({ + hits: { hits: [] }, + }); + service = assetCriticalityServiceFactory({ + assetCriticalityDataClient: mockAssetCriticalityDataClient, + experimentalFeatures: {} as ExperimentalFeatures, + }); + }); + + describe('specifying a single identifier', () => { + it('returns an empty response if identifier is not found', async () => { + const result = await service.getCriticalitiesByIdentifiers([baseIdentifier]); + + expect(result).toEqual([]); + }); + + it('returns a single criticality if identifier is found', async () => { + const hits = [buildMockCriticalityHit()]; + (mockAssetCriticalityDataClient.search as jest.Mock).mockReset().mockResolvedValueOnce({ + hits: { hits }, + }); + + const result = await service.getCriticalitiesByIdentifiers([baseIdentifier]); + + expect(result).toEqual(hits.map((hit) => hit._source)); + }); + }); + + describe('specifying multiple identifiers', () => { + it('returns an empty response if identifier is not found', async () => { + const result = await service.getCriticalitiesByIdentifiers([baseIdentifier]); + + expect(result).toEqual([]); + }); + + it('generates a single terms clause for multiple identifier values on the same field', async () => { + const multipleIdentifiers = [ + { id_field: 'user.name', id_value: 'one' }, + { id_field: 'user.name', id_value: 'other' }, + ]; + + await service.getCriticalitiesByIdentifiers(multipleIdentifiers); + + expect(mockAssetCriticalityDataClient.search).toHaveBeenCalledTimes(1); + const query = (mockAssetCriticalityDataClient.search as jest.Mock).mock.calls[0][0].query; + expect(query).toMatchObject({ + bool: { + filter: { + bool: { + should: [ + { + bool: { + must: [ + { term: { id_field: 'user.name' } }, + { terms: { id_value: ['one', 'other'] } }, + ], + }, + }, + ], + }, + }, + }, + }); + }); + + it('deduplicates identifiers', async () => { + const duplicateIdentifiers = [ + { id_field: 'user.name', id_value: 'same' }, + { id_field: 'user.name', id_value: 'same' }, + ]; + await service.getCriticalitiesByIdentifiers(duplicateIdentifiers); + + expect(mockAssetCriticalityDataClient.search).toHaveBeenCalledTimes(1); + const query = (mockAssetCriticalityDataClient.search as jest.Mock).mock.calls[0][0].query; + expect(query).toMatchObject({ + bool: { + filter: { + bool: { + should: [ + { + bool: { + must: [ + { term: { id_field: 'user.name' } }, + { terms: { id_value: ['same'] } }, + ], + }, + }, + ], + }, + }, + }, + }); + }); + + it('returns multiple criticalities if identifiers are found', async () => { + const hits = [ + buildMockCriticalityHit(), + buildMockCriticalityHit({ + id_field: 'user.name', + id_value: 'username', + criticality_level: 'very_important', + }), + ]; + + (mockAssetCriticalityDataClient.search as jest.Mock).mockReset().mockResolvedValueOnce({ + hits: { + hits, + }, + }); + const result = await service.getCriticalitiesByIdentifiers([baseIdentifier]); + expect(result).toEqual(hits.map((hit) => hit._source)); + }); + }); + + describe('arguments', () => { + it('accepts a single identifier as an array', async () => { + const identifier = { id_field: 'host.name', id_value: 'foo' }; + + expect(() => service.getCriticalitiesByIdentifiers([identifier])).not.toThrow(); + }); + + it('accepts multiple identifiers', async () => { + const identifiers = [ + { id_field: 'host.name', id_value: 'foo' }, + { id_field: 'user.name', id_value: 'bar' }, + ]; + expect(() => service.getCriticalitiesByIdentifiers(identifiers)).not.toThrow(); + }); + + it('throws an error if an empty array is provided', async () => { + await expect(() => service.getCriticalitiesByIdentifiers([])).rejects.toThrowError( + 'At least one identifier must be provided' + ); + }); + + it('throws an error if no identifier values are provided', async () => { + await expect(() => + service.getCriticalitiesByIdentifiers([{ id_field: 'host.name', id_value: '' }]) + ).rejects.toThrowError('At least one identifier must contain a valid field and value'); + }); + + it('throws an error if no valid identifier field/value pair is provided', async () => { + const identifiers = [ + { id_field: '', id_value: 'foo' }, + { id_field: 'user.name', id_value: '' }, + ]; + await expect(() => service.getCriticalitiesByIdentifiers(identifiers)).rejects.toThrowError( + 'At least one identifier must contain a valid field and value' + ); + }); + }); + + describe('error conditions', () => { + it('throws an error if the client does', async () => { + (mockAssetCriticalityDataClient.search as jest.Mock) + .mockReset() + .mockRejectedValueOnce(new Error('foo')); + await expect(() => + service.getCriticalitiesByIdentifiers([baseIdentifier]) + ).rejects.toThrowError('foo'); + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_service.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_service.ts new file mode 100644 index 0000000000000..f5320ea396008 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_service.ts @@ -0,0 +1,101 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { isEmpty } from 'lodash/fp'; +import type { ExperimentalFeatures } from '../../../../common'; +import type { AssetCriticalityRecord } from '../../../../common/api/entity_analytics'; +import type { AssetCriticalityDataClient } from './asset_criticality_data_client'; + +interface CriticalityIdentifier { + id_field: string; + id_value: string; +} + +interface IdentifierValuesByField { + [idField: string]: string[]; +} + +export interface AssetCriticalityService { + getCriticalitiesByIdentifiers: ( + identifiers: CriticalityIdentifier[] + ) => Promise; + isEnabled: () => boolean; +} + +const isCriticalityIdentifierValid = (identifier: CriticalityIdentifier): boolean => + !isEmpty(identifier.id_field) && !isEmpty(identifier.id_value); + +const groupIdentifierValuesByField = ( + identifiers: CriticalityIdentifier[] +): IdentifierValuesByField => + identifiers.reduce((acc, id) => { + acc[id.id_field] ??= []; + if (!acc[id.id_field].includes(id.id_value)) { + acc[id.id_field].push(id.id_value); + } + return acc; + }, {} as IdentifierValuesByField); + +const buildCriticalitiesQuery = (identifierValuesByField: IdentifierValuesByField) => ({ + bool: { + filter: { + bool: { + should: Object.keys(identifierValuesByField).map((idField) => ({ + bool: { + must: [ + { term: { id_field: idField } }, + { terms: { id_value: identifierValuesByField[idField] } }, + ], + }, + })), + }, + }, + }, +}); + +const getCriticalitiesByIdentifiers = async ({ + assetCriticalityDataClient, + identifiers, +}: { + assetCriticalityDataClient: AssetCriticalityDataClient; + identifiers: CriticalityIdentifier[]; +}): Promise => { + if (identifiers.length === 0) { + throw new Error('At least one identifier must be provided'); + } + const validIdentifiers = identifiers.filter((id) => isCriticalityIdentifierValid(id)); + + if (validIdentifiers.length === 0) { + throw new Error('At least one identifier must contain a valid field and value'); + } + + const identifierCount = validIdentifiers.length; + const identifierValuesByField = groupIdentifierValuesByField(validIdentifiers); + const criticalitiesQuery = buildCriticalitiesQuery(identifierValuesByField); + + const criticalitySearchResponse = await assetCriticalityDataClient.search({ + query: criticalitiesQuery, + size: identifierCount, + }); + + // @ts-expect-error @elastic/elasticsearch _source is optional + return criticalitySearchResponse.hits.hits.map((hit) => hit._source); +}; + +interface AssetCriticalityServiceFactoryOptions { + assetCriticalityDataClient: AssetCriticalityDataClient; + experimentalFeatures: ExperimentalFeatures; +} + +export const assetCriticalityServiceFactory = ({ + assetCriticalityDataClient, + experimentalFeatures, +}: AssetCriticalityServiceFactoryOptions): AssetCriticalityService => ({ + getCriticalitiesByIdentifiers: (identifiers: CriticalityIdentifier[]) => + getCriticalitiesByIdentifiers({ assetCriticalityDataClient, identifiers }), + isEnabled: () => experimentalFeatures.entityAnalyticsAssetCriticalityEnabled, +}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/configurations.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/constants.ts similarity index 67% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/configurations.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/constants.ts index c1b309c3a2f44..536230b865a8a 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/configurations.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/constants.ts @@ -5,6 +5,7 @@ * 2.0. */ import type { FieldMap } from '@kbn/alerts-as-data-utils'; +import type { AssetCriticalityRecord } from '../../../../common/api/entity_analytics'; export const assetCriticalityFieldMap: FieldMap = { '@timestamp': { @@ -33,3 +34,13 @@ export const assetCriticalityFieldMap: FieldMap = { required: false, }, } as const; + +/** + * CriticalityModifiers are used to adjust the risk score based on the criticality of the asset. + */ +export const CriticalityModifiers: Record = { + very_important: 2, + important: 1.5, + normal: 1, + not_important: 0.5, +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.test.ts new file mode 100644 index 0000000000000..9ec395223c937 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.test.ts @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { applyCriticalityToScore, normalize } from './helpers'; + +describe('applyCriticalityToScore', () => { + describe('integer scores', () => { + it('returns the original score if the modifier is undefined', () => { + const result = applyCriticalityToScore({ modifier: undefined, score: 90 }); + expect(result).toEqual(90); + }); + + it('returns the original score if the modifier is 1', () => { + const result = applyCriticalityToScore({ modifier: 1, score: 90 }); + expect(result).toEqual(90); + }); + + it('returns an increased score if the modifier is greater than 1', () => { + const result = applyCriticalityToScore({ modifier: 1.5, score: 90 }); + expect(result).toEqual(93.10344827586206); + }); + + it('returns a decreased score if the modifier is less than 1', () => { + const result = applyCriticalityToScore({ modifier: 0.5, score: 90 }); + expect(result).toEqual(81.81818181818181); + }); + + it('does not exceed a score of 100 with a previous score of 99 and a large modifier', () => { + const result = applyCriticalityToScore({ modifier: 200, score: 99 }); + expect(result).toEqual(99.99494975001262); + }); + }); + + describe('non-integer scores', () => { + it('returns the original score if the modifier is undefined', () => { + const result = applyCriticalityToScore({ modifier: undefined, score: 90.5 }); + expect(result).toEqual(90.5); + }); + + it('returns the original score if the modifier is 1', () => { + const result = applyCriticalityToScore({ modifier: 1, score: 91.84 }); + expect(result).toEqual(91.84); + }); + it('returns an increased score if the modifier is greater than 1', () => { + const result = applyCriticalityToScore({ modifier: 1.5, score: 75.98 }); + expect(result).toEqual(82.59294151750127); + }); + + it('returns a decreased score if the modifier is less than 1', () => { + const result = applyCriticalityToScore({ modifier: 0.5, score: 44.12 }); + expect(result).toEqual(28.303823453938925); + }); + + it('does not exceed a score of 100 with a high previous score and a large modifier', () => { + const result = applyCriticalityToScore({ modifier: 200, score: 99.88 }); + expect(result).toEqual(99.9993992827436); + }); + }); +}); + +describe('normalize', () => { + it('returns 0 if the number is equal to the min', () => { + const result = normalize({ number: 0, min: 0, max: 100 }); + expect(result).toEqual(0); + }); + + it('returns 100 if the number is equal to the max', () => { + const result = normalize({ number: 100, min: 0, max: 100 }); + expect(result).toEqual(100); + }); + + it('returns 50 if the number is halfway between the min and max', () => { + const result = normalize({ number: 50, min: 0, max: 100 }); + expect(result).toEqual(50); + }); + + it('defaults to a min of 0', () => { + const result = normalize({ number: 50, max: 100 }); + expect(result).toEqual(50); + }); + + describe('when the domain is diffrent than the range', () => { + it('returns 0 if the number is equal to the min', () => { + const result = normalize({ number: 20, min: 20, max: 200 }); + expect(result).toEqual(0); + }); + + it('returns 100 if the number is equal to the max', () => { + const result = normalize({ number: 40, min: 30, max: 40 }); + expect(result).toEqual(100); + }); + + it('returns 50 if the number is halfway between the min and max', () => { + const result = normalize({ number: 20, min: 0, max: 40 }); + expect(result).toEqual(50); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.ts new file mode 100644 index 0000000000000..3c12fbc89b827 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { AssetCriticalityRecord } from '../../../../common/api/entity_analytics'; +import { RISK_SCORING_NORMALIZATION_MAX } from '../risk_score/constants'; +import { CriticalityModifiers } from './constants'; + +/** + * Retrieves the criticality modifier for a given criticality level. + * + * @param criticalityLevel The criticality level for which to get the modifier. + * @returns The associated criticality modifier for the given criticality level. + */ +export const getCriticalityModifier = ( + criticalityLevel?: AssetCriticalityRecord['criticality_level'] +): number | undefined => { + if (criticalityLevel == null) { + return; + } + + return CriticalityModifiers[criticalityLevel]; +}; + +/** + * Applies asset criticality to a normalized risk score using bayesian inference. + * @param modifier - The criticality modifier to apply to the score. + * @param score - The normalized risk score to which the criticality modifier is applied + * + * @returns The risk score with the criticality modifier applied. + */ +export const applyCriticalityToScore = ({ + modifier, + score, +}: { + modifier: number | undefined; + score: number; +}): number => { + if (modifier == null) { + return score; + } + + return bayesianUpdate({ max: RISK_SCORING_NORMALIZATION_MAX, modifier, score }); +}; + +/** + * Updates a score with the given modifier using bayesian inference. + * @param modifier - The modifier to be applied to the score. + * @param score - The score to modifiers are applied + * @param max - The maximum value of the score. + * + * @returns The updated score with modifiers applied + */ +export const bayesianUpdate = ({ + max, + modifier, + score, +}: { + max: number; + modifier: number; + score: number; +}) => { + const priorProbability = score / (max - score); + const newProbability = priorProbability * modifier; + return (max * newProbability) / (1 + newProbability); +}; + +/** + * Normalizes a number to the range [0, 100] + * + * @param number - The number to be normalized + * @param min - The minimum possible value of the number. Defaults to 0. + * @param max - The maximum possible value of the number + * + * @returns The updated score with modifiers applied + */ +export const normalize = ({ + number, + min = 0, + max, +}: { + number: number; + min?: number; + max: number; +}) => ((number - min) / (max - min)) * 100; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/index.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/index.ts new file mode 100644 index 0000000000000..7b8b38945dae5 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './asset_criticality_service'; +export * from './asset_criticality_data_client'; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_and_persist_risk_scores.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_and_persist_risk_scores.ts index 77258d313034c..25bc1bddd99fa 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_and_persist_risk_scores.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_and_persist_risk_scores.ts @@ -9,10 +9,12 @@ import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import type { RiskScoreDataClient } from './risk_score_data_client'; import type { CalculateAndPersistScoresParams, CalculateAndPersistScoresResponse } from '../types'; +import type { AssetCriticalityService } from '../asset_criticality/asset_criticality_service'; import { calculateRiskScores } from './calculate_risk_scores'; export const calculateAndPersistRiskScores = async ( params: CalculateAndPersistScoresParams & { + assetCriticalityService: AssetCriticalityService; esClient: ElasticsearchClient; logger: Logger; spaceId: string; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.mock.ts index 20db1f8d61735..fbfaaf11140d8 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.mock.ts @@ -23,7 +23,6 @@ const buildRiskScoreBucketMock = (overrides: Partial = {}): Ris value: { score: 20, normalized_score: 30.0, - level: 'Unknown', notes: [], category_1_score: 30, category_1_count: 1, @@ -88,11 +87,15 @@ const buildResponseMock = ( '@timestamp': '2021-08-19T20:55:59.000Z', id_field: 'host.name', id_value: 'hostname', + criticality_level: 'important', + criticality_modifier: 1.5, calculated_level: 'Unknown', calculated_score: 20, calculated_score_norm: 30, category_1_score: 30, category_1_count: 12, + category_2_score: 0, + category_2_count: 0, notes: [], inputs: [ { diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.test.ts index f75fd94c42d30..30d3d2f0566ee 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.test.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.test.ts @@ -7,6 +7,7 @@ import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import { elasticsearchServiceMock, loggingSystemMock } from '@kbn/core/server/mocks'; +import { assetCriticalityServiceMock } from '../asset_criticality/asset_criticality_service.mock'; import { calculateRiskScores } from './calculate_risk_scores'; import { calculateRiskScoresMock } from './calculate_risk_scores.mock'; @@ -21,6 +22,7 @@ describe('calculateRiskScores()', () => { logger = loggingSystemMock.createLogger(); params = { afterKeys: {}, + assetCriticalityService: assetCriticalityServiceMock.create(), esClient, logger, index: 'index', @@ -184,7 +186,7 @@ describe('calculateRiskScores()', () => { '@timestamp': expect.any(String), id_field: expect.any(String), id_value: expect.any(String), - calculated_level: 'Unknown', + calculated_level: 'Low', calculated_score: expect.any(Number), calculated_score_norm: expect.any(Number), category_1_score: expect.any(Number), @@ -217,18 +219,44 @@ describe('calculateRiskScores()', () => { }); describe('error conditions', () => { - beforeEach(() => { - // stub out a rejected response + it('raises an error if elasticsearch client rejects', async () => { (esClient.search as jest.Mock).mockRejectedValueOnce({ aggregations: calculateRiskScoresMock.buildAggregationResponse(), }); - }); - it('raises an error if elasticsearch client rejects', () => { - expect.assertions(1); - expect(() => calculateRiskScores(params)).rejects.toEqual({ + await expect(() => calculateRiskScores(params)).rejects.toEqual({ aggregations: calculateRiskScoresMock.buildAggregationResponse(), }); }); + + describe('when the asset criticality service throws an error', () => { + beforeEach(() => { + (esClient.search as jest.Mock).mockResolvedValueOnce({ + aggregations: calculateRiskScoresMock.buildAggregationResponse(), + }); + ( + params.assetCriticalityService.getCriticalitiesByIdentifiers as jest.Mock + ).mockRejectedValueOnce(new Error('foo')); + }); + + it('logs the error but proceeds if asset criticality service throws', async () => { + await expect(calculateRiskScores(params)).resolves.toEqual( + expect.objectContaining({ + scores: expect.objectContaining({ + host: expect.arrayContaining([ + expect.objectContaining({ + calculated_level: expect.any(String), + id_field: expect.any(String), + id_value: expect.any(String), + }), + ]), + }), + }) + ); + expect(logger.warn).toHaveBeenCalledWith( + 'Error retrieving criticality: Error: foo. Scoring will proceed without criticality information.' + ); + }); + }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.ts index a877bfd0f8e60..d9af3457d6915 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.ts @@ -17,14 +17,22 @@ import { ALERT_WORKFLOW_STATUS, EVENT_KIND, } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; -import type { - AfterKeys, - IdentifierType, - RiskWeights, - RiskScore, +import { + type AfterKeys, + type IdentifierType, + type RiskWeights, + type RiskScore, + getRiskLevel, + RiskCategories, } from '../../../../common/entity_analytics/risk_engine'; -import { RiskCategories } from '../../../../common/entity_analytics/risk_engine'; import { withSecuritySpan } from '../../../utils/with_security_span'; +import type { AssetCriticalityRecord } from '../../../../common/api/entity_analytics'; +import type { AssetCriticalityService } from '../asset_criticality/asset_criticality_service'; +import { + applyCriticalityToScore, + getCriticalityModifier, + normalize, +} from '../asset_criticality/helpers'; import { getAfterKeyForIdentifierType, getFieldForIdentifierAgg } from './helpers'; import { buildCategoryCountDeclarations, @@ -39,34 +47,68 @@ import type { CalculateScoresResponse, RiskScoreBucket, } from '../types'; +import { + RISK_SCORING_INPUTS_COUNT_MAX, + RISK_SCORING_SUM_MAX, + RISK_SCORING_SUM_VALUE, +} from './constants'; -const bucketToResponse = ({ +const formatForResponse = ({ bucket, + criticality, now, identifierField, + includeNewFields, }: { bucket: RiskScoreBucket; + criticality?: AssetCriticalityRecord; now: string; identifierField: string; -}): RiskScore => ({ - '@timestamp': now, - id_field: identifierField, - id_value: bucket.key[identifierField], - calculated_level: bucket.risk_details.value.level, - calculated_score: bucket.risk_details.value.score, - calculated_score_norm: bucket.risk_details.value.normalized_score, - category_1_score: bucket.risk_details.value.category_1_score, - category_1_count: bucket.risk_details.value.category_1_count, - notes: bucket.risk_details.value.notes, - inputs: bucket.inputs.hits.hits.map((riskInput) => ({ - id: riskInput._id, - index: riskInput._index, - description: `Alert from Rule: ${riskInput.fields?.[ALERT_RULE_NAME]?.[0] ?? 'RULE_NOT_FOUND'}`, - category: RiskCategories.category_1, - risk_score: riskInput.fields?.[ALERT_RISK_SCORE]?.[0] ?? undefined, - timestamp: riskInput.fields?.['@timestamp']?.[0] ?? undefined, - })), -}); + includeNewFields: boolean; +}): RiskScore => { + const criticalityModifier = getCriticalityModifier(criticality?.criticality_level); + const normalizedScoreWithCriticality = applyCriticalityToScore({ + score: bucket.risk_details.value.normalized_score, + modifier: criticalityModifier, + }); + const calculatedLevel = getRiskLevel(normalizedScoreWithCriticality); + const categoryTwoScore = + normalizedScoreWithCriticality - bucket.risk_details.value.normalized_score; + const categoryTwoCount = criticalityModifier ? 1 : 0; + + const newFields = { + category_2_score: categoryTwoScore, + category_2_count: categoryTwoCount, + criticality_level: criticality?.criticality_level, + criticality_modifier: criticalityModifier, + }; + + return { + '@timestamp': now, + id_field: identifierField, + id_value: bucket.key[identifierField], + calculated_level: calculatedLevel, + calculated_score: bucket.risk_details.value.score, + calculated_score_norm: normalizedScoreWithCriticality, + category_1_score: normalize({ + number: bucket.risk_details.value.category_1_score, + max: RISK_SCORING_SUM_MAX, + }), + category_1_count: bucket.risk_details.value.category_1_count, + notes: bucket.risk_details.value.notes, + inputs: bucket.inputs.hits.hits.map((riskInput) => ({ + id: riskInput._id, + index: riskInput._index, + description: `Alert from Rule: ${ + riskInput.fields?.[ALERT_RULE_NAME]?.[0] ?? 'RULE_NOT_FOUND' + }`, + category: RiskCategories.category_1, + risk_score: riskInput.fields?.[ALERT_RISK_SCORE]?.[0] ?? undefined, + timestamp: riskInput.fields?.['@timestamp']?.[0] ?? undefined, + })), + ...(includeNewFields ? newFields : {}), + }; +}; const filterFromRange = (range: CalculateScoresParams['range']): QueryDslQueryContainer => ({ range: { '@timestamp': { lt: range.end, gte: range.start } }, @@ -108,22 +150,6 @@ const buildReduceScript = ({ results['score'] = total_score; results['normalized_score'] = score_norm; - if (score_norm < 20) { - results['level'] = 'Unknown' - } - else if (score_norm >= 20 && score_norm < 40) { - results['level'] = 'Low' - } - else if (score_norm >= 40 && score_norm < 70) { - results['level'] = 'Moderate' - } - else if (score_norm >= 70 && score_norm < 90) { - results['level'] = 'High' - } - else if (score_norm >= 90) { - results['level'] = 'Critical' - } - return results; `; }; @@ -184,9 +210,9 @@ const buildIdentifierTypeAggregation = ({ `, combine_script: 'return state;', params: { - max_risk_inputs_per_identity: 999999, - p: 1.5, - risk_cap: 261.2, + max_risk_inputs_per_identity: RISK_SCORING_INPUTS_COUNT_MAX, + p: RISK_SCORING_SUM_VALUE, + risk_cap: RISK_SCORING_SUM_MAX, }, reduce_script: buildReduceScript({ globalIdentifierTypeWeight }), }, @@ -195,8 +221,55 @@ const buildIdentifierTypeAggregation = ({ }; }; +const processScores = async ({ + assetCriticalityService, + buckets, + identifierField, + logger, + now, +}: { + assetCriticalityService: AssetCriticalityService; + buckets: RiskScoreBucket[]; + identifierField: string; + logger: Logger; + now: string; +}): Promise => { + if (buckets.length === 0) { + return []; + } + + if (!assetCriticalityService.isEnabled()) { + return buckets.map((bucket) => + formatForResponse({ bucket, now, identifierField, includeNewFields: false }) + ); + } + + const identifiers = buckets.map((bucket) => ({ + id_field: identifierField, + id_value: bucket.key[identifierField], + })); + + let criticalities: AssetCriticalityRecord[] = []; + try { + criticalities = await assetCriticalityService.getCriticalitiesByIdentifiers(identifiers); + } catch (e) { + logger.warn( + `Error retrieving criticality: ${e}. Scoring will proceed without criticality information.` + ); + } + + return buckets.map((bucket) => { + const criticality = criticalities.find( + (c) => c.id_field === identifierField && c.id_value === bucket.key[identifierField] + ); + + return formatForResponse({ bucket, criticality, identifierField, now, includeNewFields: true }); + }); +}; + export const calculateRiskScores = async ({ afterKeys: userAfterKeys, + assetCriticalityService, debug, esClient, filter: userFilter, @@ -208,6 +281,7 @@ export const calculateRiskScores = async ({ runtimeMappings, weights, }: { + assetCriticalityService: AssetCriticalityService; esClient: ElasticsearchClient; logger: Logger; } & CalculateScoresParams): Promise => @@ -274,16 +348,27 @@ export const calculateRiskScores = async ({ user: response.aggregations.user?.after_key, }; + const hostScores = await processScores({ + assetCriticalityService, + buckets: hostBuckets, + identifierField: 'host.name', + logger, + now, + }); + const userScores = await processScores({ + assetCriticalityService, + buckets: userBuckets, + identifierField: 'user.name', + logger, + now, + }); + return { ...(debug ? { request, response } : {}), after_keys: afterKeys, scores: { - host: hostBuckets.map((bucket) => - bucketToResponse({ bucket, identifierField: 'host.name', now }) - ), - user: userBuckets.map((bucket) => - bucketToResponse({ bucket, identifierField: 'user.name', now }) - ), + host: hostScores, + user: userScores, }, }; }); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/constants.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/constants.ts new file mode 100644 index 0000000000000..57e67960f96e2 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/constants.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * The risk scoring algorithm uses a Riemann zeta function to sum an entity's risk inputs to a known, finite value (@see RISK_SCORING_SUM_MAX). It does so by assigning each input a weight based on its position in the list (ordered by score) of inputs. This value represents the complex variable s of Re(s) in traditional Riemann zeta function notation. + */ +export const RISK_SCORING_SUM_VALUE = 1.5; + +/** + * Represents the maximum possible risk score sum. This value is derived from RISK_SCORING_SUM_VALUE, but we store the precomputed value here to be used more conveniently in normalization. + * @see RISK_SCORING_SUM_VALUE + */ +export const RISK_SCORING_SUM_MAX = 261.2; + +/** + * The risk scoring algorithm can only process a finite number of risk inputs per identity; this value represents the maximum number of inputs that will be processed. + */ +export const RISK_SCORING_INPUTS_COUNT_MAX = 999999; + +/** + * This value represents the maximum possible risk score after normalization. + */ +export const RISK_SCORING_NORMALIZATION_MAX = 100; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_engine_data_writer.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_engine_data_writer.test.ts index ca2ad354320a6..271d5511e6b75 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_engine_data_writer.test.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_engine_data_writer.test.ts @@ -51,6 +51,10 @@ describe('RiskEngineDataWriter', () => { "calculated_score_norm": 85.332, "category_1_count": 12, "category_1_score": 85, + "category_2_count": 0, + "category_2_score": 0, + "criticality_level": "very_important", + "criticality_modifier": 2, "id_field": "host.name", "id_value": "hostname", "inputs": Array [], @@ -73,6 +77,10 @@ describe('RiskEngineDataWriter', () => { "calculated_score_norm": 85.332, "category_1_count": 12, "category_1_score": 85, + "category_2_count": 0, + "category_2_score": 0, + "criticality_level": "very_important", + "criticality_modifier": 2, "id_field": "host.name", "id_value": "hostname", "inputs": Array [], @@ -117,6 +125,10 @@ describe('RiskEngineDataWriter', () => { "calculated_score_norm": 85.332, "category_1_count": 12, "category_1_score": 85, + "category_2_count": 0, + "category_2_score": 0, + "criticality_level": "very_important", + "criticality_modifier": 2, "id_field": "user.name", "id_value": "username_1", "inputs": Array [], @@ -139,6 +151,10 @@ describe('RiskEngineDataWriter', () => { "calculated_score_norm": 85.332, "category_1_count": 12, "category_1_score": 85, + "category_2_count": 0, + "category_2_score": 0, + "criticality_level": "very_important", + "criticality_modifier": 2, "id_field": "user.name", "id_value": "username_2", "inputs": Array [], @@ -189,6 +205,10 @@ describe('RiskEngineDataWriter', () => { "calculated_score_norm": 85.332, "category_1_count": 12, "category_1_score": 85, + "category_2_count": 0, + "category_2_score": 0, + "criticality_level": "very_important", + "criticality_modifier": 2, "id_field": "host.name", "id_value": "hostname_1", "inputs": Array [], @@ -211,6 +231,10 @@ describe('RiskEngineDataWriter', () => { "calculated_score_norm": 85.332, "category_1_count": 12, "category_1_score": 85, + "category_2_count": 0, + "category_2_score": 0, + "criticality_level": "very_important", + "criticality_modifier": 2, "id_field": "user.name", "id_value": "username_1", "inputs": Array [], @@ -233,6 +257,10 @@ describe('RiskEngineDataWriter', () => { "calculated_score_norm": 85.332, "category_1_count": 12, "category_1_score": 85, + "category_2_count": 0, + "category_2_score": 0, + "criticality_level": "very_important", + "criticality_modifier": 2, "id_field": "user.name", "id_value": "username_2", "inputs": Array [], diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_service.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_service.mock.ts index e72852f6ea47a..5353d38fcaefa 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_service.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_service.mock.ts @@ -17,6 +17,10 @@ const createRiskScoreMock = (overrides: Partial = {}): RiskScore => ( calculated_score_norm: 85.332, category_1_score: 85, category_1_count: 12, + category_2_count: 0, + category_2_score: 0, + criticality_level: 'very_important', + criticality_modifier: 2, notes: [], inputs: [], ...overrides, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_service.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_service.ts index a89835c6c7327..c62e4c3ead828 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_service.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_service.ts @@ -16,6 +16,7 @@ import type { import { calculateRiskScores } from './calculate_risk_scores'; import { calculateAndPersistRiskScores } from './calculate_and_persist_risk_scores'; import type { RiskEngineDataClient } from '../risk_engine/risk_engine_data_client'; +import type { AssetCriticalityService } from '../asset_criticality/asset_criticality_service'; import type { RiskScoreDataClient } from './risk_score_data_client'; import type { RiskInputsIndexResponse } from './get_risk_inputs_index'; import { scheduleLatestTransformNow } from '../utils/transforms'; @@ -31,6 +32,7 @@ export interface RiskScoreService { } export interface RiskScoreServiceFactoryParams { + assetCriticalityService: AssetCriticalityService; esClient: ElasticsearchClient; logger: Logger; riskEngineDataClient: RiskEngineDataClient; @@ -39,15 +41,24 @@ export interface RiskScoreServiceFactoryParams { } export const riskScoreServiceFactory = ({ + assetCriticalityService, esClient, logger, riskEngineDataClient, riskScoreDataClient, spaceId, }: RiskScoreServiceFactoryParams): RiskScoreService => ({ - calculateScores: (params) => calculateRiskScores({ ...params, esClient, logger }), + calculateScores: (params) => + calculateRiskScores({ ...params, assetCriticalityService, esClient, logger }), calculateAndPersistScores: (params) => - calculateAndPersistRiskScores({ ...params, esClient, logger, riskScoreDataClient, spaceId }), + calculateAndPersistRiskScores({ + ...params, + assetCriticalityService, + esClient, + logger, + riskScoreDataClient, + spaceId, + }), getConfiguration: async () => riskEngineDataClient.getConfiguration(), getRiskInputsIndex: async (params) => riskScoreDataClient.getRiskInputsIndex(params), scheduleLatestTransformNow: () => scheduleLatestTransformNow({ namespace: spaceId, esClient }), diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_weights.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_weights.ts index f0af4360b8631..de1754ba3de21 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_weights.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_weights.ts @@ -54,7 +54,7 @@ const getWeightForIdentifierType = (weight: RiskWeight, identifierType: Identifi }; export const buildCategoryScoreDeclarations = (): string => { - return RISK_CATEGORIES.map((riskCategory) => `results['${riskCategory}_score'] = 0;`).join(''); + return RISK_CATEGORIES.map((riskCategory) => `results['${riskCategory}_score'] = 0.0;`).join(''); }; export const buildCategoryCountDeclarations = (): string => { diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.test.ts index 0a62695dfd680..fb5c366193cb7 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.test.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.test.ts @@ -9,6 +9,7 @@ import { riskScoreCalculationRoute } from './calculation'; import { loggerMock } from '@kbn/logging-mocks'; +import type { ExperimentalFeatures } from '../../../../../common'; import { RISK_SCORE_CALCULATION_URL } from '../../../../../common/constants'; import { serverMock, @@ -44,7 +45,7 @@ describe('risk score calculation route', () => { clients.appClient.getAlertsIndex.mockReturnValue('default-alerts-index'); (riskScoreServiceFactory as jest.Mock).mockReturnValue(mockRiskScoreService); - riskScoreCalculationRoute(server.router, logger); + riskScoreCalculationRoute(server.router, logger, {} as ExperimentalFeatures); }); const buildRequest = (overrides: object = {}) => { diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.ts index 1822c038b7d1d..71f4d05712d68 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.ts @@ -14,12 +14,18 @@ import { RISK_SCORE_CALCULATION_URL, } from '../../../../../common/constants'; import { riskScoreCalculationRequestSchema } from '../../../../../common/entity_analytics/risk_engine/risk_score_calculation/request_schema'; +import type { ExperimentalFeatures } from '../../../../../common'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; +import { assetCriticalityServiceFactory } from '../../asset_criticality'; import { riskScoreServiceFactory } from '../risk_score_service'; import { getRiskInputsIndex } from '../get_risk_inputs_index'; -export const riskScoreCalculationRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => { +export const riskScoreCalculationRoute = ( + router: SecuritySolutionPluginRouter, + logger: Logger, + experimentalFeatures: ExperimentalFeatures +) => { router.versioned .post({ path: RISK_SCORE_CALCULATION_URL, @@ -42,8 +48,14 @@ export const riskScoreCalculationRoute = (router: SecuritySolutionPluginRouter, const spaceId = securityContext.getSpaceId(); const riskEngineDataClient = securityContext.getRiskEngineDataClient(); const riskScoreDataClient = securityContext.getRiskScoreDataClient(); + const assetCriticalityDataClient = securityContext.getAssetCriticalityDataClient(); + const assetCriticalityService = assetCriticalityServiceFactory({ + assetCriticalityDataClient, + experimentalFeatures, + }); const riskScoreService = riskScoreServiceFactory({ + assetCriticalityService, esClient, logger, riskEngineDataClient, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.test.ts index 9a525a5bae0d5..71d108058a10d 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.test.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.test.ts @@ -7,6 +7,7 @@ import { loggerMock } from '@kbn/logging-mocks'; +import type { ExperimentalFeatures } from '../../../../../common'; import { RISK_SCORE_PREVIEW_URL } from '../../../../../common/constants'; import { RiskCategories, @@ -48,7 +49,7 @@ describe('POST risk_engine/preview route', () => { clients.appClient.getAlertsIndex.mockReturnValue('default-alerts-index'); (riskScoreServiceFactory as jest.Mock).mockReturnValue(mockRiskScoreService); - riskScorePreviewRoute(server.router, logger); + riskScorePreviewRoute(server.router, logger, {} as ExperimentalFeatures); }); const buildRequest = (body: object = {}) => diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.ts index 13f3ee8a9df07..db11cf84e9049 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.ts @@ -15,12 +15,18 @@ import { RISK_SCORE_PREVIEW_URL, } from '../../../../../common/constants'; import { riskScorePreviewRequestSchema } from '../../../../../common/entity_analytics/risk_engine/risk_score_preview/request_schema'; +import type { ExperimentalFeatures } from '../../../../../common'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; +import { assetCriticalityServiceFactory } from '../../asset_criticality'; import { riskScoreServiceFactory } from '../risk_score_service'; import { getRiskInputsIndex } from '../get_risk_inputs_index'; -export const riskScorePreviewRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => { +export const riskScorePreviewRoute = ( + router: SecuritySolutionPluginRouter, + logger: Logger, + experimentalFeatures: ExperimentalFeatures +) => { router.versioned .post({ access: 'internal', @@ -43,8 +49,14 @@ export const riskScorePreviewRoute = (router: SecuritySolutionPluginRouter, logg const spaceId = securityContext.getSpaceId(); const riskEngineDataClient = securityContext.getRiskEngineDataClient(); const riskScoreDataClient = securityContext.getRiskScoreDataClient(); + const assetCriticalityDataClient = securityContext.getAssetCriticalityDataClient(); + const assetCriticalityService = assetCriticalityServiceFactory({ + assetCriticalityDataClient, + experimentalFeatures, + }); const riskScoreService = riskScoreServiceFactory({ + assetCriticalityService, esClient, logger, riskEngineDataClient, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts index 45562ac8d38a9..bc3d5054980dc 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts @@ -11,6 +11,7 @@ import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { loggerMock } from '@kbn/logging-mocks'; import type { AnalyticsServiceSetup } from '@kbn/core/public'; +import type { ExperimentalFeatures } from '../../../../../common'; import type { RiskScoreService } from '../risk_score_service'; import { riskScoreServiceMock } from '../risk_score_service.mock'; import { riskScoringTaskMock } from './risk_scoring_task.mock'; @@ -47,6 +48,7 @@ describe('Risk Scoring Task', () => { it('registers the task with TaskManager', () => { expect(mockTaskManagerSetup.registerTaskDefinitions).not.toHaveBeenCalled(); registerRiskScoringTask({ + experimentalFeatures: {} as ExperimentalFeatures, getStartServices: mockCore.getStartServices, kibanaVersion: '8.10.0', taskManager: mockTaskManagerSetup, @@ -59,6 +61,7 @@ describe('Risk Scoring Task', () => { it('does nothing if TaskManager is not available', () => { expect(mockTaskManagerSetup.registerTaskDefinitions).not.toHaveBeenCalled(); registerRiskScoringTask({ + experimentalFeatures: {} as ExperimentalFeatures, getStartServices: mockCore.getStartServices, kibanaVersion: '8.10.0', taskManager: undefined, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts index a1539167bbaf4..421fb4092b928 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts @@ -18,7 +18,11 @@ import type { TaskManagerStartContract, } from '@kbn/task-manager-plugin/server'; import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; -import type { AfterKeys, IdentifierType } from '../../../../../common/entity_analytics/risk_engine'; +import { + type AfterKeys, + type IdentifierType, + RiskScoreEntity, +} from '../../../../../common/entity_analytics/risk_engine'; import type { StartPlugins } from '../../../../plugin'; import { type RiskScoreService, riskScoreServiceFactory } from '../risk_score_service'; import { RiskEngineDataClient } from '../../risk_engine/risk_engine_data_client'; @@ -31,12 +35,16 @@ import { } from './state'; import { INTERVAL, SCOPE, TIMEOUT, TYPE, VERSION } from './constants'; import { buildScopedInternalSavedObjectsClientUnsafe, convertRangeToISO } from './helpers'; -import { RiskScoreEntity } from '../../../../../common/entity_analytics/risk_engine/types'; +import type { ExperimentalFeatures } from '../../../../../common'; import { RISK_SCORE_EXECUTION_SUCCESS_EVENT, RISK_SCORE_EXECUTION_ERROR_EVENT, RISK_SCORE_EXECUTION_CANCELLATION_EVENT, } from '../../../telemetry/event_based/events'; +import { + AssetCriticalityDataClient, + assetCriticalityServiceFactory, +} from '../../asset_criticality'; const logFactory = (logger: Logger, taskId: string) => @@ -50,12 +58,14 @@ const getTaskId = (namespace: string): string => `${TYPE}:${namespace}:${VERSION type GetRiskScoreService = (namespace: string) => Promise; export const registerRiskScoringTask = ({ + experimentalFeatures, getStartServices, kibanaVersion, logger, taskManager, telemetry, }: { + experimentalFeatures: ExperimentalFeatures; getStartServices: StartServicesAccessor; kibanaVersion: string; logger: Logger; @@ -71,6 +81,17 @@ export const registerRiskScoringTask = ({ getStartServices().then(([coreStart, _]) => { const esClient = coreStart.elasticsearch.client.asInternalUser; const soClient = buildScopedInternalSavedObjectsClientUnsafe({ coreStart, namespace }); + + const assetCriticalityDataClient = new AssetCriticalityDataClient({ + esClient, + logger, + namespace, + }); + const assetCriticalityService = assetCriticalityServiceFactory({ + assetCriticalityDataClient, + experimentalFeatures, + }); + const riskEngineDataClient = new RiskEngineDataClient({ logger, kibanaVersion, @@ -87,6 +108,7 @@ export const registerRiskScoringTask = ({ }); return riskScoreServiceFactory({ + assetCriticalityService, esClient, logger, riskEngineDataClient, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/types.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/types.ts index acdb1982011d2..ea2464b8058a7 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/types.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/types.ts @@ -117,7 +117,6 @@ export interface RiskScoreBucket { score: number; normalized_score: number; notes: string[]; - level: string; category_1_score: number; category_1_count: number; }; diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 53141fc1751ce..01154dc06f5f6 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -183,6 +183,7 @@ export class Plugin implements ISecuritySolutionPlugin { if (experimentalFeatures.riskScoringPersistence) { registerRiskScoringTask({ + experimentalFeatures, getStartServices: core.getStartServices, kibanaVersion: pluginContext.env.packageInfo.version, logger: this.logger, diff --git a/x-pack/plugins/security_solution/server/request_context_factory.ts b/x-pack/plugins/security_solution/server/request_context_factory.ts index 3deaaa103caa6..3f1d9f818e431 100644 --- a/x-pack/plugins/security_solution/server/request_context_factory.ts +++ b/x-pack/plugins/security_solution/server/request_context_factory.ts @@ -27,7 +27,7 @@ import type { EndpointAuthz } from '../common/endpoint/types/authz'; import type { EndpointAppContextService } from './endpoint/endpoint_app_context_services'; import { RiskEngineDataClient } from './lib/entity_analytics/risk_engine/risk_engine_data_client'; import { RiskScoreDataClient } from './lib/entity_analytics/risk_score/risk_score_data_client'; -import { AssetCriticalityDataClient } from './lib/entity_analytics/asset_criticality/asset_criticality_data_client'; +import { AssetCriticalityDataClient } from './lib/entity_analytics/asset_criticality'; export interface IRequestContextFactory { create( diff --git a/x-pack/plugins/security_solution/server/routes/index.ts b/x-pack/plugins/security_solution/server/routes/index.ts index ce863fb861076..b32543ad7612d 100644 --- a/x-pack/plugins/security_solution/server/routes/index.ts +++ b/x-pack/plugins/security_solution/server/routes/index.ts @@ -159,8 +159,8 @@ export const initRoutes = ( } if (config.experimentalFeatures.riskScoringRoutesEnabled) { - riskScorePreviewRoute(router, logger); - riskScoreCalculationRoute(router, logger); + riskScorePreviewRoute(router, logger, config.experimentalFeatures); + riskScoreCalculationRoute(router, logger, config.experimentalFeatures); riskEngineStatusRoute(router); riskEngineInitRoute(router, getStartServices); riskEngineEnableRoute(router, getStartServices); diff --git a/x-pack/plugins/security_solution/server/types.ts b/x-pack/plugins/security_solution/server/types.ts index a44572ae07eae..7833c1dff6b8a 100644 --- a/x-pack/plugins/security_solution/server/types.ts +++ b/x-pack/plugins/security_solution/server/types.ts @@ -31,7 +31,7 @@ import type { EndpointAuthz } from '../common/endpoint/types/authz'; import type { EndpointInternalFleetServicesInterface } from './endpoint/services/fleet'; import type { RiskEngineDataClient } from './lib/entity_analytics/risk_engine/risk_engine_data_client'; import type { RiskScoreDataClient } from './lib/entity_analytics/risk_score/risk_score_data_client'; -import type { AssetCriticalityDataClient } from './lib/entity_analytics/asset_criticality/asset_criticality_data_client'; +import type { AssetCriticalityDataClient } from './lib/entity_analytics/asset_criticality'; export { AppClient }; export interface SecuritySolutionApiRequestHandlerContext { diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_score_calculation.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_score_calculation.ts index 03f7734e42628..d4f5be1eff225 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_score_calculation.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_score_calculation.ts @@ -23,6 +23,9 @@ import { readRiskScores, normalizeScores, waitForRiskScoresToBePresent, + assetCriticalityRouteHelpersFactory, + cleanAssetCriticality, + waitForAssetCriticalityToBePresent, } from '../../utils'; import { FtrProviderContext } from '../../../../ftr_provider_context'; @@ -116,17 +119,17 @@ export default ({ getService }: FtrProviderContext): void => { const scores = await readRiskScores(es); expect(scores.length).to.eql(1); - expect(normalizeScores(scores)).to.eql([ - { - calculated_level: 'Unknown', - calculated_score: 21, - calculated_score_norm: 8.039816232771823, - category_1_score: 21, - category_1_count: 1, - id_field: 'host.name', - id_value: 'host-1', - }, - ]); + const [score] = normalizeScores(scores); + + expect(score).to.eql({ + calculated_level: 'Unknown', + calculated_score: 21, + calculated_score_norm: 8.039816232771823, + category_1_score: 8.039816232771821, + category_1_count: 1, + id_field: 'host.name', + id_value: 'host-1', + }); }); describe('paging through calculations', () => { @@ -269,6 +272,60 @@ export default ({ getService }: FtrProviderContext): void => { expect(scores.length).to.eql(10); }); }); + + describe('@skipInServerless with asset criticality data', () => { + const assetCriticalityRoutes = assetCriticalityRouteHelpersFactory(supertest); + + beforeEach(async () => { + await assetCriticalityRoutes.upsert({ + id_field: 'host.name', + id_value: 'host-1', + criticality_level: 'important', + }); + }); + + afterEach(async () => { + await cleanAssetCriticality({ log, es }); + }); + + it('calculates and persists risk scores with additional criticality metadata and modifiers', async () => { + const documentId = uuidv4(); + await indexListOfDocuments([buildDocument({ host: { name: 'host-1' } }, documentId)]); + await waitForAssetCriticalityToBePresent({ es, log }); + + const results = await calculateRiskScoreAfterRuleCreationAndExecution(documentId); + expect(results).to.eql({ + after_keys: { host: { 'host.name': 'host-1' } }, + errors: [], + scores_written: 1, + }); + + await waitForRiskScoresToBePresent({ es, log }); + const scores = await readRiskScores(es); + expect(scores.length).to.eql(1); + + const [score] = normalizeScores(scores); + expect(score).to.eql({ + criticality_level: 'important', + criticality_modifier: 1.5, + calculated_level: 'Unknown', + calculated_score: 21, + calculated_score_norm: 11.59366948840633, + category_1_score: 8.039816232771821, + category_1_count: 1, + id_field: 'host.name', + id_value: 'host-1', + }); + const [rawScore] = scores; + + expect( + rawScore.host?.risk.category_1_score! + rawScore.host?.risk.category_2_score! + ).to.be.within( + score.calculated_score_norm! - 0.000000000000001, + score.calculated_score_norm! + 0.000000000000001 + ); + }); + }); }); }); }; diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_score_preview.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_score_preview.ts index e4284cdb5b837..bfb415bac02a8 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_score_preview.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_score_preview.ts @@ -18,10 +18,13 @@ import { dataGeneratorFactory, } from '../../../detections_response/utils'; import { + assetCriticalityRouteHelpersFactory, buildDocument, + cleanAssetCriticality, createAndSyncRuleAndAlertsFactory, deleteAllRiskScores, sanitizeScores, + waitForAssetCriticalityToBePresent, } from '../../utils'; import { FtrProviderContext } from '../../../../ftr_provider_context'; @@ -99,18 +102,23 @@ export default ({ getService }: FtrProviderContext): void => { await indexListOfDocuments([buildDocument({ host: { name: 'host-1' } }, documentId)]); const body = await getRiskScoreAfterRuleCreationAndExecution(documentId); + const [score] = sanitizeScores(body.scores.host!); + const [rawScore] = body.scores.host!; + + expect(score).to.eql({ + calculated_level: 'Unknown', + calculated_score: 21, + calculated_score_norm: 8.039816232771823, + category_1_count: 1, + category_1_score: 8.039816232771821, + id_field: 'host.name', + id_value: 'host-1', + }); - expect(sanitizeScores(body.scores.host!)).to.eql([ - { - calculated_level: 'Unknown', - calculated_score: 21, - calculated_score_norm: 8.039816232771823, - category_1_count: 1, - category_1_score: 21, - id_field: 'host.name', - id_value: 'host-1', - }, - ]); + expect(rawScore.category_1_score! + rawScore.category_2_score!).to.be.within( + score.calculated_score_norm! - 0.000000000000001, + score.calculated_score_norm! + 0.000000000000001 + ); }); it('calculates risk from two alerts, each representing a unique host', async () => { @@ -130,7 +138,7 @@ export default ({ getService }: FtrProviderContext): void => { calculated_score: 21, calculated_score_norm: 8.039816232771823, category_1_count: 1, - category_1_score: 21, + category_1_score: 8.039816232771821, id_field: 'host.name', id_value: 'host-1', }, @@ -139,7 +147,7 @@ export default ({ getService }: FtrProviderContext): void => { calculated_score: 21, calculated_score_norm: 8.039816232771823, category_1_count: 1, - category_1_score: 21, + category_1_score: 8.039816232771821, id_field: 'host.name', id_value: 'host-2', }, @@ -163,7 +171,7 @@ export default ({ getService }: FtrProviderContext): void => { calculated_score: 28.42462120245875, calculated_score_norm: 10.88232052161514, category_1_count: 2, - category_1_score: 28, + category_1_score: 10.882320521615142, id_field: 'host.name', id_value: 'host-1', }, @@ -185,7 +193,7 @@ export default ({ getService }: FtrProviderContext): void => { calculated_score: 47.25513506055279, calculated_score_norm: 18.091552473412246, category_1_count: 30, - category_1_score: 37, + category_1_score: 18.091552473412246, id_field: 'host.name', id_value: 'host-1', }, @@ -210,7 +218,7 @@ export default ({ getService }: FtrProviderContext): void => { calculated_score: 47.25513506055279, calculated_score_norm: 18.091552473412246, category_1_count: 30, - category_1_score: 37, + category_1_score: 18.091552473412246, id_field: 'host.name', id_value: 'host-1', }, @@ -219,7 +227,7 @@ export default ({ getService }: FtrProviderContext): void => { calculated_score: 21, calculated_score_norm: 8.039816232771823, category_1_count: 1, - category_1_score: 21, + category_1_score: 8.039816232771821, id_field: 'host.name', id_value: 'host-2', }, @@ -241,7 +249,7 @@ export default ({ getService }: FtrProviderContext): void => { calculated_score: 50.67035607277805, calculated_score_norm: 19.399064346392823, category_1_count: 100, - category_1_score: 37, + category_1_score: 19.399064346392823, id_field: 'host.name', id_value: 'host-1', }, @@ -266,7 +274,7 @@ export default ({ getService }: FtrProviderContext): void => { calculated_score: 241.2874098703716, calculated_score_norm: 92.37649688758484, category_1_count: 100, - category_1_score: 209, + category_1_score: 92.37649688758484, id_field: 'host.name', id_value: 'host-1', }, @@ -297,7 +305,7 @@ export default ({ getService }: FtrProviderContext): void => { calculated_score: 254.91456029175757, calculated_score_norm: 97.59362951445543, category_1_count: 1000, - category_1_score: 209, + category_1_score: 97.59362951445543, id_field: 'host.name', id_value: 'host-1', }, @@ -393,7 +401,7 @@ export default ({ getService }: FtrProviderContext): void => { calculated_score: 225.1106801442913, calculated_score_norm: 86.18326192354185, category_1_count: 100, - category_1_score: 203, + category_1_score: 86.18326192354185, id_field: 'host.name', id_value: 'host-1', }, @@ -422,7 +430,7 @@ export default ({ getService }: FtrProviderContext): void => { calculated_score: 120.6437049351858, calculated_score_norm: 46.18824844379242, category_1_count: 100, - category_1_score: 209, + category_1_score: 92.37649688758484, id_field: 'host.name', id_value: 'host-1', }, @@ -449,7 +457,7 @@ export default ({ getService }: FtrProviderContext): void => { calculated_score: 168.9011869092601, calculated_score_norm: 64.66354782130938, category_1_count: 100, - category_1_score: 209, + category_1_score: 92.37649688758484, id_field: 'user.name', id_value: 'user-1', }, @@ -478,7 +486,7 @@ export default ({ getService }: FtrProviderContext): void => { calculated_score: 93.23759116471251, calculated_score_norm: 35.695861854790394, category_1_count: 50, - category_1_score: 209, + category_1_score: 89.23965463697598, id_field: 'host.name', id_value: 'host-1', }, @@ -490,7 +498,7 @@ export default ({ getService }: FtrProviderContext): void => { calculated_score: 186.47518232942502, calculated_score_norm: 71.39172370958079, category_1_count: 50, - category_1_score: 209, + category_1_score: 89.23965463697598, id_field: 'user.name', id_value: 'user-1', }, @@ -527,7 +535,7 @@ export default ({ getService }: FtrProviderContext): void => { calculated_level: 'Low', calculated_score: 93.2375911647125, calculated_score_norm: 35.695861854790394, - category_1_score: 77, + category_1_score: 35.69586185479039, category_1_count: 50, id_field: 'host.name', id_value: 'host-1', @@ -539,7 +547,7 @@ export default ({ getService }: FtrProviderContext): void => { calculated_level: 'High', calculated_score: 186.475182329425, calculated_score_norm: 71.39172370958079, - category_1_score: 165, + category_1_score: 71.39172370958077, category_1_count: 50, id_field: 'user.name', id_value: 'user-1', @@ -547,6 +555,58 @@ export default ({ getService }: FtrProviderContext): void => { ]); }); }); + + describe('@skipInServerless with asset criticality data', () => { + const assetCriticalityRoutes = assetCriticalityRouteHelpersFactory(supertest); + + beforeEach(async () => { + await assetCriticalityRoutes.upsert({ + id_field: 'host.name', + id_value: 'host-1', + criticality_level: 'very_important', + }); + }); + + afterEach(async () => { + await cleanAssetCriticality({ log, es }); + }); + + it('calculates and persists risk scores with additional criticality metadata and modifiers', async () => { + const documentId = uuidv4(); + await indexListOfDocuments([ + buildDocument({ host: { name: 'host-1' } }, documentId), + buildDocument({ host: { name: 'host-2' } }, documentId), + ]); + await waitForAssetCriticalityToBePresent({ es, log }); + + const body = await getRiskScoreAfterRuleCreationAndExecution(documentId, { + alerts: 2, + }); + + expect(sanitizeScores(body.scores.host!)).to.eql([ + { + criticality_level: 'very_important', + criticality_modifier: 2.0, + calculated_level: 'Unknown', + calculated_score: 21, + calculated_score_norm: 14.8830616583983, + category_1_count: 1, + category_1_score: 8.039816232771821, + id_field: 'host.name', + id_value: 'host-1', + }, + { + calculated_level: 'Unknown', + calculated_score: 21, + calculated_score_norm: 8.039816232771823, + category_1_count: 1, + category_1_score: 8.039816232771821, + id_field: 'host.name', + id_value: 'host-2', + }, + ]); + }); + }); }); }); }; diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution.ts index 7ebfb568e8cd3..1f9c886b932f8 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution.ts @@ -23,6 +23,9 @@ import { getRiskEngineTask, waitForRiskEngineTaskToBeGone, cleanRiskEngine, + assetCriticalityRouteHelpersFactory, + cleanAssetCriticality, + waitForAssetCriticalityToBePresent, } from '../../../utils'; import { FtrProviderContext } from '../../../../../ftr_provider_context'; @@ -157,7 +160,8 @@ export default ({ getService }: FtrProviderContext): void => { await riskEngineRoutes.disable(); }); - describe('when task interval is modified', () => { + // Temporary, expected failure: See https://github.com/elastic/security-team/issues/8012 + describe.skip('when task interval is modified', () => { beforeEach(async () => { await updateRiskEngineConfigSO({ attributes: { @@ -179,8 +183,7 @@ export default ({ getService }: FtrProviderContext): void => { }); }); - // FLAKY: https://github.com/elastic/kibana/issues/171132 - describe.skip('with some alerts containing hosts and others containing users', () => { + describe('with some alerts containing hosts and others containing users', () => { let hostId: string; let userId: string; @@ -212,20 +215,68 @@ export default ({ getService }: FtrProviderContext): void => { alerts: 20, riskScore: 40, }); - - await riskEngineRoutes.init(); }); it('@skipInQA calculates and persists risk scores for both types of entities', async () => { + await riskEngineRoutes.init(); await waitForRiskScoresToBePresent({ es, log, scoreCount: 20 }); const riskScores = await readRiskScores(es); - expect(riskScores.length).to.eql(20); + expect(riskScores.length).to.be.greaterThan(0); const scoredIdentifiers = normalizeScores(riskScores).map( ({ id_field: idField }) => idField ); - expect(scoredIdentifiers.includes('host.name')).to.be(true); - expect(scoredIdentifiers.includes('user.name')).to.be(true); + expect(scoredIdentifiers).to.contain('host.name'); + expect(scoredIdentifiers).to.contain('user.name'); + }); + + context('@skipInServerless with asset criticality data', () => { + const assetCriticalityRoutes = assetCriticalityRouteHelpersFactory(supertest); + + beforeEach(async () => { + await assetCriticalityRoutes.upsert({ + id_field: 'host.name', + id_value: 'host-1', + criticality_level: 'very_important', + }); + }); + + afterEach(async () => { + await cleanAssetCriticality({ log, es }); + }); + + it('calculates risk scores with asset criticality data', async () => { + await waitForAssetCriticalityToBePresent({ es, log }); + await riskEngineRoutes.init(); + await waitForRiskScoresToBePresent({ es, log, scoreCount: 20 }); + const riskScores = await readRiskScores(es); + + expect(riskScores.length).to.be.greaterThan(0); + const assetCriticalityLevels = riskScores.map( + (riskScore) => riskScore.host?.risk.criticality_level + ); + const assetCriticalityModifiers = riskScores.map( + (riskScore) => riskScore.host?.risk.criticality_modifier + ); + + expect(assetCriticalityLevels).to.contain('very_important'); + expect(assetCriticalityModifiers).to.contain(2); + + const scoreWithCriticality = riskScores.find((score) => score.host?.name === 'host-1'); + expect(normalizeScores([scoreWithCriticality!])).to.eql([ + { + id_field: 'host.name', + id_value: 'host-1', + criticality_level: 'very_important', + criticality_modifier: 2, + calculated_level: 'Moderate', + calculated_score: 79.81345973382406, + calculated_score_norm: 46.809565696393314, + category_1_count: 10, + category_1_score: 30.55645472198471, + }, + ]); + }); }); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/asset_criticality.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/asset_criticality.ts index b745d1d0f705f..6abcb908f6083 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/asset_criticality.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/asset_criticality.ts @@ -15,10 +15,11 @@ import { ASSET_CRITICALITY_URL, ASSET_CRITICALITY_PRIVILEGES_URL, } from '@kbn/security-solution-plugin/common/constants'; +import type { AssetCriticalityRecord } from '@kbn/security-solution-plugin/common/api/entity_analytics'; import type { Client } from '@elastic/elasticsearch'; import type { ToolingLog } from '@kbn/tooling-log'; import querystring from 'querystring'; -import { routeWithNamespace } from '../../detections_response/utils'; +import { routeWithNamespace, waitFor } from '../../detections_response/utils'; export const getAssetCriticalityIndex = (namespace?: string) => `.asset-criticality.asset-criticality-${namespace ?? 'default'}`; @@ -123,3 +124,51 @@ export const assetCriticalityRouteHelpersFactoryNoAuth = ( .send() .expect(200), }); + +/** + * Function to read asset criticality records from ES. By default, it reads from the asset criticality index in the default space, but this can be overridden with the + * `index` parameter. + * + * @param {string[]} index - the index or indices to read criticality from. + * @param {number} size - the size parameter of the query + */ +export const readAssetCriticality = async ( + es: Client, + index: string[] = [getAssetCriticalityIndex()], + size: number = 1000 +): Promise => { + const results = await es.search({ + index, + size, + }); + return results.hits.hits.map((hit) => hit._source as AssetCriticalityRecord); +}; + +/** + * Function to read asset criticality from ES and wait for them to be + * present/readable. By default, it reads from the asset criticality index in the + * default space, but this can be overridden with the `index` parameter. + * + * @param {string[]} index - the index or indices to read asset criticality from. + * @param {number} docCount - the number of asset criticality docs to wait for. Defaults to 1. + */ +export const waitForAssetCriticalityToBePresent = async ({ + es, + log, + index = [getAssetCriticalityIndex()], + docCount = 1, +}: { + es: Client; + log: ToolingLog; + index?: string[]; + docCount?: number; +}): Promise => { + await waitFor( + async () => { + const criticalities = await readAssetCriticality(es, index, docCount + 10); + return criticalities.length >= docCount; + }, + 'waitForAssetCriticalityToBePresent', + log + ); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/index.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/index.ts index dacdf5052c912..7ff049a997da1 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/index.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/index.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + export * from './risk_engine'; export * from './get_risk_engine_stats'; export * from './asset_criticality'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/risk_engine.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/risk_engine.ts index 5a29900f5e8d6..fb242e72bc898 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/risk_engine.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/risk_engine.ts @@ -37,11 +37,15 @@ import { } from '../../detections_response/utils'; const sanitizeScore = (score: Partial): Partial => { - delete score['@timestamp']; - delete score.inputs; - delete score.notes; - // delete score.category_1_score; - return score; + const { + '@timestamp': timestamp, + inputs, + notes, + category_2_count: cat2Count, + category_2_score: cat2Score, + ...rest + } = score; + return rest; }; export const sanitizeScores = (scores: Array>): Array> => From 94bdc0d5212412e41e8281a5235654546e2102cb Mon Sep 17 00:00:00 2001 From: Kevin Qualters <56408403+kqualters-elastic@users.noreply.github.com> Date: Thu, 4 Jan 2024 17:26:32 -0500 Subject: [PATCH 031/100] [Security Solution] [Timelines] Fix FilterManager being undefined when opening timeline from url (#171443) ## Summary Filter manager is not populated within redux if a user navigates to a url with timeline opened as the first step of entering the app. InitializeTimeline action is called, but the reducer just ignores any params at all if the initialize flag is set to true. Since this is only used in 2 places, and only 1 of which has an argument other than timelineId, I think this solution is fine. Should only ever result in fixing this bug it seems, as filterManager is either created anew or comes directly from the model. Issue: https://github.com/elastic/kibana/issues/171437 ### 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 --- .../public/timelines/store/helpers.ts | 8 ++- .../investigations/timelines/filters.cy.ts | 52 +++++++++++++++++++ .../cypress/screens/timeline.ts | 6 +++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/filters.cy.ts diff --git a/x-pack/plugins/security_solution/public/timelines/store/helpers.ts b/x-pack/plugins/security_solution/public/timelines/store/helpers.ts index 3206bb96e89ad..456d716f529f5 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/helpers.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/helpers.ts @@ -1475,7 +1475,13 @@ export const setInitializeTimelineSettings = ({ initialized: true, }, } - : timelineById; + : { + ...timelineById, + [id]: { + ...timeline, + ...timelineSettingsProps, + }, + }; }; interface ApplyDeltaToTableColumnWidth { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/filters.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/filters.cy.ts new file mode 100644 index 0000000000000..d87639a231f58 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/filters.cy.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { login } from '../../../tasks/login'; +import { visitWithTimeRange } from '../../../tasks/navigation'; +import { + createNewTimeline, + addNameAndDescriptionToTimeline, + populateTimeline, +} from '../../../tasks/timeline'; +import { openTimelineUsingToggle } from '../../../tasks/security_main'; +import { ALERTS_URL } from '../../../urls/navigation'; +import { getTimeline } from '../../../objects/timeline'; +import { + GET_TIMELINE_GRID_CELL, + TIMELINE_FILTER_FOR, + TIMELINE_FILTER_OUT, + TIMELINE_EVENT, + TIMELINE_FILTER_BADGE_ENABLED, +} from '../../../screens/timeline'; + +describe( + `timleine cell actions`, + { + tags: ['@ess'], + }, + () => { + beforeEach(() => { + login(); + visitWithTimeRange(ALERTS_URL); + openTimelineUsingToggle(); + createNewTimeline(); + addNameAndDescriptionToTimeline(getTimeline()); + populateTimeline(); + }); + it('filter in', () => { + cy.get(GET_TIMELINE_GRID_CELL('event.category')).trigger('mouseover'); + cy.get(TIMELINE_FILTER_FOR).should('be.visible').click(); + cy.get(TIMELINE_FILTER_BADGE_ENABLED).should('be.visible'); + }); + + it('filter out', () => { + cy.get(GET_TIMELINE_GRID_CELL('event.category')).trigger('mouseover'); + cy.get(TIMELINE_FILTER_OUT).should('be.visible').click(); + cy.get(TIMELINE_EVENT).should('not.exist'); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/timeline.ts b/x-pack/test/security_solution_cypress/cypress/screens/timeline.ts index b498d3d6bc32b..2794a111e94c2 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/timeline.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/timeline.ts @@ -284,6 +284,12 @@ export const HOVER_ACTIONS = { SHOW_TOP: '[data-test-subj=show-top-field]', }; +export const TIMELINE_FILTER_OUT = '[data-test-subj="filter-out-value"]'; + +export const TIMELINE_FILTER_FOR = '[data-test-subj="filter-for-value"]'; + +export const TIMELINE_FILTER_BADGE_ENABLED = '[data-test-subj~="filter-enabled"]'; + export const GET_TIMELINE_HEADER = (fieldName: string) => { return `[data-test-subj="timeline"] [data-test-subj="header-text-${fieldName}"]`; }; From 2fcbea2d7cff47e0911096c311bb63ce43036ad7 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Thu, 4 Jan 2024 15:30:17 -0700 Subject: [PATCH 032/100] [geo_containment alert] replace alertFactory with alertsClient (#173867) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes https://github.com/elastic/kibana/issues/167321 PR does not provide any custom fields for payload because geo containment alert has very little usage and will be [disabled in serverless](https://github.com/elastic/kibana/pull/174121), with the goal of deprecating and removing geo containment alert in the future. --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Mike Côté --- .../geo_containment/executor.test.ts | 86 ++++++-------- .../rule_types/geo_containment/executor.ts | 18 ++- .../get_entities_and_generate_alerts.test.ts | 107 +++++++----------- .../lib/get_entities_and_generate_alerts.ts | 12 +- .../rule_types/geo_containment/rule_type.ts | 3 + 5 files changed, 97 insertions(+), 129 deletions(-) diff --git a/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/executor.test.ts b/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/executor.test.ts index cec83d2cf9e71..cb0606594c093 100644 --- a/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/executor.test.ts +++ b/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/executor.test.ts @@ -5,50 +5,16 @@ * 2.0. */ -import _ from 'lodash'; import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; import { RuleExecutorServicesMock, alertsMock } from '@kbn/alerting-plugin/server/mocks'; import sampleAggsJsonResponse from './tests/es_sample_response.json'; import sampleShapesJsonResponse from './tests/es_sample_response_shapes.json'; import { executor } from './executor'; -import type { - GeoContainmentRuleParams, - GeoContainmentAlertInstanceState, - GeoContainmentAlertInstanceContext, -} from './types'; +import type { GeoContainmentRuleParams, GeoContainmentAlertInstanceContext } from './types'; -const alertFactory = (contextKeys: unknown[], testAlertActionArr: unknown[]) => ({ - create: (instanceId: string) => { - const alertInstance = alertsMock.createAlertFactory.create< - GeoContainmentAlertInstanceState, - GeoContainmentAlertInstanceContext - >(); - (alertInstance.scheduleActions as jest.Mock).mockImplementation( - (actionGroupId: string, context?: GeoContainmentAlertInstanceContext) => { - // Check subset of alert for comparison to expected results - // @ts-ignore - const contextSubset = _.pickBy(context, (v, k) => contextKeys.includes(k)); - testAlertActionArr.push({ - actionGroupId, - instanceId, - context: contextSubset, - }); - } - ); - return alertInstance; - }, - alertLimit: { - getValue: () => 1000, - setLimitReached: () => {}, - }, - done: () => ({ getRecoveredAlerts: () => [] }), -}); - -describe('getGeoContainmentExecutor', () => { - // Params needed for all tests - const expectedAlertResults = [ +describe('executor', () => { + const expectedAlerts = [ { - actionGroupId: 'Tracked entity contained', context: { containingBoundaryId: 'kFATGXkBsFLYN2Tj6AAk', entityDocumentId: 'ZVBoGXkBsFLYN2Tj1wmV', @@ -58,7 +24,6 @@ describe('getGeoContainmentExecutor', () => { instanceId: '0-kFATGXkBsFLYN2Tj6AAk', }, { - actionGroupId: 'Tracked entity contained', context: { containingBoundaryId: 'kFATGXkBsFLYN2Tj6AAk', entityDocumentId: 'ZlBoGXkBsFLYN2Tj1wmV', @@ -68,7 +33,7 @@ describe('getGeoContainmentExecutor', () => { instanceId: '1-kFATGXkBsFLYN2Tj6AAk', }, ]; - const testAlertActionArr: unknown[] = []; + const previousStartedAt = new Date('2021-04-27T16:56:11.923Z'); const startedAt = new Date('2021-04-29T16:56:11.923Z'); const geoContainmentParams: GeoContainmentRuleParams = { @@ -99,7 +64,6 @@ describe('getGeoContainmentExecutor', () => { // Boundary test mocks const boundaryCall = jest.fn(); const esAggCall = jest.fn(); - const contextKeys = Object.keys(expectedAlertResults[0].context); const esClient = elasticsearchServiceMock.createElasticsearchClient(); // @ts-ignore incomplete return type esClient.search.mockResponseImplementation(({ index }) => { @@ -112,10 +76,26 @@ describe('getGeoContainmentExecutor', () => { } }); - const alertServicesWithSearchMock: RuleExecutorServicesMock = { + const alerts: unknown[] = []; + const servicesMock: RuleExecutorServicesMock = { ...alertsMock.createRuleExecutorServices(), // @ts-ignore - alertFactory: alertFactory(contextKeys, testAlertActionArr), + alertsClient: { + getRecoveredAlerts: () => { + return []; + }, + report: ({ id, context }: { id: string; context: GeoContainmentAlertInstanceContext }) => { + alerts.push({ + context: { + containingBoundaryId: context.containingBoundaryId, + entityDocumentId: context.entityDocumentId, + entityId: context.entityId, + entityLocation: context.entityLocation, + }, + instanceId: id, + }); + }, + }, // @ts-ignore scopedClusterClient: { asCurrentUser: esClient, @@ -124,7 +104,7 @@ describe('getGeoContainmentExecutor', () => { beforeEach(() => { jest.clearAllMocks(); - testAlertActionArr.length = 0; + alerts.length = 0; }); test('should query for shapes if state does not contain shapes', async () => { @@ -132,7 +112,7 @@ describe('getGeoContainmentExecutor', () => { previousStartedAt, startedAt, // @ts-ignore - services: alertServicesWithSearchMock, + services: servicesMock, params: geoContainmentParams, // @ts-ignore rule: { @@ -145,7 +125,7 @@ describe('getGeoContainmentExecutor', () => { expect(boundaryCall.mock.calls.length).toBe(1); expect(esAggCall.mock.calls.length).toBe(1); } - expect(testAlertActionArr).toMatchObject(expectedAlertResults); + expect(alerts).toMatchObject(expectedAlerts); }); test('should query for shapes if boundaries request meta changes', async () => { @@ -153,7 +133,7 @@ describe('getGeoContainmentExecutor', () => { previousStartedAt, startedAt, // @ts-ignore - services: alertServicesWithSearchMock, + services: servicesMock, params: geoContainmentParams, // @ts-ignore rule: { @@ -172,7 +152,7 @@ describe('getGeoContainmentExecutor', () => { expect(boundaryCall.mock.calls.length).toBe(1); expect(esAggCall.mock.calls.length).toBe(1); } - expect(testAlertActionArr).toMatchObject(expectedAlertResults); + expect(alerts).toMatchObject(expectedAlerts); }); test('should not query for shapes if state contains shapes', async () => { @@ -180,7 +160,7 @@ describe('getGeoContainmentExecutor', () => { previousStartedAt, startedAt, // @ts-ignore - services: alertServicesWithSearchMock, + services: servicesMock, params: geoContainmentParams, // @ts-ignore rule: { @@ -192,7 +172,7 @@ describe('getGeoContainmentExecutor', () => { expect(boundaryCall.mock.calls.length).toBe(0); expect(esAggCall.mock.calls.length).toBe(1); } - expect(testAlertActionArr).toMatchObject(expectedAlertResults); + expect(alerts).toMatchObject(expectedAlerts); }); test('should carry through shapes filters in state to next call unmodified', async () => { @@ -200,7 +180,7 @@ describe('getGeoContainmentExecutor', () => { previousStartedAt, startedAt, // @ts-ignore - services: alertServicesWithSearchMock, + services: servicesMock, params: geoContainmentParams, // @ts-ignore rule: { @@ -211,7 +191,7 @@ describe('getGeoContainmentExecutor', () => { if (executionResult && executionResult.state.shapesFilters) { expect(executionResult.state.shapesFilters).toEqual(geoContainmentState.shapesFilters); } - expect(testAlertActionArr).toMatchObject(expectedAlertResults); + expect(alerts).toMatchObject(expectedAlerts); }); test('should return previous locations map', async () => { @@ -239,7 +219,7 @@ describe('getGeoContainmentExecutor', () => { previousStartedAt, startedAt, // @ts-ignore - services: alertServicesWithSearchMock, + services: servicesMock, params: geoContainmentParams, // @ts-ignore rule: { @@ -250,6 +230,6 @@ describe('getGeoContainmentExecutor', () => { if (executionResult && executionResult.state.prevLocationMap) { expect(executionResult.state.prevLocationMap).toEqual(expectedPrevLocationMap); } - expect(testAlertActionArr).toMatchObject(expectedAlertResults); + expect(alerts).toMatchObject(expectedAlerts); }); }); diff --git a/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/executor.ts b/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/executor.ts index e7681eb4dee2d..b6462aec32497 100644 --- a/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/executor.ts +++ b/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/executor.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { AlertsClientError } from '@kbn/alerting-plugin/server'; import { RuleExecutorOptions } from '../../types'; import { canSkipBoundariesFetch, @@ -45,6 +46,11 @@ export async function executor({ boundaryNameField: params.boundaryNameField, boundaryIndexQuery: params.boundaryIndexQuery, }; + + if (!services.alertsClient) { + throw new AlertsClientError(); + } + const { shapesFilters, shapesIdsNamesMap } = state.shapesFilters && canSkipBoundariesFetch(boundariesRequestMeta, state.boundariesRequestMeta) @@ -82,14 +88,13 @@ export async function executor({ const { activeEntities, inactiveEntities } = getEntitiesAndGenerateAlerts( prevLocationMap, currLocationMap, - services.alertFactory, + services.alertsClient, shapesIdsNamesMap, windowEnd ); - const { getRecoveredAlerts } = services.alertFactory.done(); - for (const recoveredAlert of getRecoveredAlerts()) { - const recoveredAlertId = recoveredAlert.getId(); + for (const recoveredAlert of services.alertsClient.getRecoveredAlerts()) { + const recoveredAlertId = recoveredAlert.alert.getId(); try { const context = getRecoveredAlertContext({ alertId: recoveredAlertId, @@ -98,7 +103,10 @@ export async function executor({ windowEnd, }); if (context) { - recoveredAlert.setContext(context); + services.alertsClient?.setAlertData({ + id: recoveredAlertId, + context, + }); } } catch (e) { logger.warn(`Unable to set alert context for recovered alert, error: ${e.message}`); diff --git a/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/lib/get_entities_and_generate_alerts.test.ts b/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/lib/get_entities_and_generate_alerts.test.ts index 339e53b03056b..c8e8dd8faa4d5 100644 --- a/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/lib/get_entities_and_generate_alerts.test.ts +++ b/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/lib/get_entities_and_generate_alerts.test.ts @@ -5,47 +5,28 @@ * 2.0. */ -import _ from 'lodash'; -import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; import { getEntitiesAndGenerateAlerts } from './get_entities_and_generate_alerts'; import { OTHER_CATEGORY } from '../constants'; -import type { - GeoContainmentAlertInstanceState, - GeoContainmentAlertInstanceContext, -} from '../types'; - -const alertFactory = (contextKeys: unknown[], testAlertActionArr: unknown[]) => ({ - create: (instanceId: string) => { - const alertInstance = alertsMock.createAlertFactory.create< - GeoContainmentAlertInstanceState, - GeoContainmentAlertInstanceContext - >(); - (alertInstance.scheduleActions as jest.Mock).mockImplementation( - (actionGroupId: string, context?: GeoContainmentAlertInstanceContext) => { - // Check subset of alert for comparison to expected results - // @ts-ignore - const contextSubset = _.pickBy(context, (v, k) => contextKeys.includes(k)); - testAlertActionArr.push({ - actionGroupId, - instanceId, - context: contextSubset, - }); - } - ); - return alertInstance; - }, - alertLimit: { - getValue: () => 1000, - setLimitReached: () => {}, - }, - done: () => ({ getRecoveredAlerts: () => [] }), -}); +import type { GeoContainmentAlertInstanceContext } from '../types'; describe('getEntitiesAndGenerateAlerts', () => { - const testAlertActionArr: unknown[] = []; + const alerts: unknown[] = []; + const mockAlertsClient = { + report: ({ id, context }: { id: string; context: GeoContainmentAlertInstanceContext }) => { + alerts.push({ + context: { + containingBoundaryId: context.containingBoundaryId, + entityDocumentId: context.entityDocumentId, + entityId: context.entityId, + entityLocation: context.entityLocation, + }, + instanceId: id, + }); + }, + } as any; // eslint-disable-line @typescript-eslint/no-explicit-any + beforeEach(() => { - jest.clearAllMocks(); - testAlertActionArr.length = 0; + alerts.length = 0; }); const currLocationMap = new Map([ @@ -87,9 +68,8 @@ describe('getEntitiesAndGenerateAlerts', () => { ], ]); - const expectedAlertResults = [ + const expectedAlerts = [ { - actionGroupId: 'Tracked entity contained', context: { containingBoundaryId: '123', entityDocumentId: 'docId1', @@ -99,7 +79,6 @@ describe('getEntitiesAndGenerateAlerts', () => { instanceId: 'a-123', }, { - actionGroupId: 'Tracked entity contained', context: { containingBoundaryId: '456', entityDocumentId: 'docId2', @@ -109,7 +88,6 @@ describe('getEntitiesAndGenerateAlerts', () => { instanceId: 'b-456', }, { - actionGroupId: 'Tracked entity contained', context: { containingBoundaryId: '789', entityDocumentId: 'docId3', @@ -119,7 +97,6 @@ describe('getEntitiesAndGenerateAlerts', () => { instanceId: 'c-789', }, ]; - const contextKeys = Object.keys(expectedAlertResults[0].context); const emptyShapesIdsNamesMap = {}; const currentDateTime = new Date(); @@ -129,12 +106,12 @@ describe('getEntitiesAndGenerateAlerts', () => { const { activeEntities } = getEntitiesAndGenerateAlerts( emptyPrevLocationMap, currLocationMap, - alertFactory(contextKeys, testAlertActionArr), + mockAlertsClient, emptyShapesIdsNamesMap, currentDateTime ); expect(activeEntities).toEqual(currLocationMap); - expect(testAlertActionArr).toMatchObject(expectedAlertResults); + expect(alerts).toMatchObject(expectedAlerts); }); test('should overwrite older identical entity entries', () => { @@ -155,12 +132,12 @@ describe('getEntitiesAndGenerateAlerts', () => { const { activeEntities } = getEntitiesAndGenerateAlerts( prevLocationMapWithIdenticalEntityEntry, currLocationMap, - alertFactory(contextKeys, testAlertActionArr), + mockAlertsClient, emptyShapesIdsNamesMap, currentDateTime ); expect(activeEntities).toEqual(currLocationMap); - expect(testAlertActionArr).toMatchObject(expectedAlertResults); + expect(alerts).toMatchObject(expectedAlerts); }); test('should preserve older non-identical entity entries', () => { @@ -178,30 +155,28 @@ describe('getEntitiesAndGenerateAlerts', () => { ], ], ]); - const expectedAlertResultsPlusD = [ - { - actionGroupId: 'Tracked entity contained', - context: { - containingBoundaryId: '999', - entityDocumentId: 'docId7', - entityId: 'd', - entityLocation: 'POINT (0 0)', - }, - instanceId: 'd-999', - }, - ...expectedAlertResults, - ]; const { activeEntities } = getEntitiesAndGenerateAlerts( prevLocationMapWithNonIdenticalEntityEntry, currLocationMap, - alertFactory(contextKeys, testAlertActionArr), + mockAlertsClient, emptyShapesIdsNamesMap, currentDateTime ); expect(activeEntities).not.toEqual(currLocationMap); expect(activeEntities.has('d')).toBeTruthy(); - expect(testAlertActionArr).toMatchObject(expectedAlertResultsPlusD); + expect(alerts).toMatchObject([ + { + context: { + containingBoundaryId: '999', + entityDocumentId: 'docId7', + entityId: 'd', + entityLocation: 'POINT (0 0)', + }, + instanceId: 'd-999', + }, + ...expectedAlerts, + ]); }); test('should remove "other" entries and schedule the expected number of actions', () => { @@ -219,7 +194,7 @@ describe('getEntitiesAndGenerateAlerts', () => { const { activeEntities, inactiveEntities } = getEntitiesAndGenerateAlerts( emptyPrevLocationMap, currLocationMapWithOther, - alertFactory(contextKeys, testAlertActionArr), + mockAlertsClient, emptyShapesIdsNamesMap, currentDateTime ); @@ -240,7 +215,7 @@ describe('getEntitiesAndGenerateAlerts', () => { ], ]) ); - expect(testAlertActionArr).toMatchObject(expectedAlertResults); + expect(alerts).toMatchObject(expectedAlerts); }); test('should generate multiple alerts per entity if found in multiple shapes in interval', () => { @@ -271,7 +246,7 @@ describe('getEntitiesAndGenerateAlerts', () => { getEntitiesAndGenerateAlerts( emptyPrevLocationMap, currLocationMapWithThreeMore, - alertFactory(contextKeys, testAlertActionArr), + mockAlertsClient, emptyShapesIdsNamesMap, currentDateTime ); @@ -279,7 +254,7 @@ describe('getEntitiesAndGenerateAlerts', () => { currLocationMapWithThreeMore.forEach((v) => { numEntitiesInShapes += v.length; }); - expect(testAlertActionArr.length).toEqual(numEntitiesInShapes); + expect(alerts.length).toEqual(numEntitiesInShapes); }); test('should not return entity as active entry if most recent location is "other"', () => { @@ -311,7 +286,7 @@ describe('getEntitiesAndGenerateAlerts', () => { const { activeEntities } = getEntitiesAndGenerateAlerts( emptyPrevLocationMap, currLocationMapWithOther, - alertFactory(contextKeys, testAlertActionArr), + mockAlertsClient, emptyShapesIdsNamesMap, currentDateTime ); @@ -346,7 +321,7 @@ describe('getEntitiesAndGenerateAlerts', () => { const { activeEntities } = getEntitiesAndGenerateAlerts( emptyPrevLocationMap, currLocationMapWithOther, - alertFactory(contextKeys, testAlertActionArr), + mockAlertsClient, emptyShapesIdsNamesMap, currentDateTime ); diff --git a/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/lib/get_entities_and_generate_alerts.ts b/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/lib/get_entities_and_generate_alerts.ts index c0d372e08dced..5ec7fcedb5eed 100644 --- a/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/lib/get_entities_and_generate_alerts.ts +++ b/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/lib/get_entities_and_generate_alerts.ts @@ -17,11 +17,11 @@ import { getAlertId, getContainedAlertContext } from './alert_context'; export function getEntitiesAndGenerateAlerts( prevLocationMap: Map, currLocationMap: Map, - alertFactory: RuleExecutorServices< + alertsClient: RuleExecutorServices< GeoContainmentAlertInstanceState, GeoContainmentAlertInstanceContext, typeof ActionGroupId - >['alertFactory'], + >['alertsClient'], shapesIdsNamesMap: Record, windowEnd: Date ): { @@ -43,9 +43,11 @@ export function getEntitiesAndGenerateAlerts( shapesIdsNamesMap, windowEnd, }); - alertFactory - .create(getAlertId(entityName, context.containingBoundaryName)) - .scheduleActions(ActionGroupId, context); + alertsClient!.report({ + id: getAlertId(entityName, context.containingBoundaryName), + actionGroup: ActionGroupId, + context, + }); } }); diff --git a/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/rule_type.ts b/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/rule_type.ts index 832e6499dc02b..f7ea3b3601453 100644 --- a/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/rule_type.ts +++ b/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/rule_type.ts @@ -17,6 +17,7 @@ import type { } from './types'; import { executor } from './executor'; import { ActionGroupId, RecoveryActionGroupId, GEO_CONTAINMENT_ID } from './constants'; +import { STACK_ALERTS_AAD_CONFIG } from '../constants'; const actionVariables = { context: [ @@ -200,5 +201,7 @@ export function getRuleType(): GeoContainmentRuleType { return injectEntityAndBoundaryIds(params, references); }, }, + // @ts-ignore + alerts: STACK_ALERTS_AAD_CONFIG, }; } From 178583c11dcdbb5dbe0a09db4060fdbe92b8dd6a Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 5 Jan 2024 01:00:18 -0500 Subject: [PATCH 033/100] [api-docs] 2024-01-05 Daily api_docs build (#174318) Generated by https://buildkite.com/elastic/kibana-api-docs-daily/builds/573 --- api_docs/actions.mdx | 2 +- api_docs/advanced_settings.mdx | 2 +- .../ai_assistant_management_observability.mdx | 2 +- .../ai_assistant_management_selection.mdx | 2 +- api_docs/aiops.mdx | 2 +- api_docs/alerting.devdocs.json | 12 - api_docs/alerting.mdx | 2 +- api_docs/apm.mdx | 2 +- api_docs/apm_data_access.mdx | 2 +- api_docs/asset_manager.mdx | 2 +- api_docs/banners.mdx | 2 +- api_docs/bfetch.mdx | 2 +- api_docs/canvas.mdx | 2 +- api_docs/cases.mdx | 2 +- api_docs/charts.mdx | 2 +- api_docs/cloud.mdx | 2 +- api_docs/cloud_data_migration.mdx | 2 +- api_docs/cloud_defend.mdx | 2 +- api_docs/cloud_experiments.mdx | 2 +- api_docs/cloud_security_posture.mdx | 2 +- api_docs/console.mdx | 2 +- api_docs/content_management.mdx | 2 +- api_docs/controls.mdx | 2 +- api_docs/custom_integrations.mdx | 2 +- api_docs/dashboard.mdx | 2 +- api_docs/dashboard_enhanced.mdx | 2 +- api_docs/data.mdx | 2 +- api_docs/data_query.mdx | 2 +- api_docs/data_search.mdx | 2 +- api_docs/data_view_editor.mdx | 2 +- api_docs/data_view_field_editor.mdx | 2 +- api_docs/data_view_management.mdx | 2 +- api_docs/data_views.mdx | 2 +- api_docs/data_visualizer.mdx | 2 +- api_docs/dataset_quality.mdx | 2 +- api_docs/deprecations_by_api.mdx | 4 +- api_docs/deprecations_by_plugin.mdx | 3 +- api_docs/deprecations_by_team.mdx | 2 +- api_docs/dev_tools.mdx | 2 +- api_docs/discover.mdx | 2 +- api_docs/discover_enhanced.mdx | 2 +- api_docs/ecs_data_quality_dashboard.mdx | 2 +- api_docs/elastic_assistant.mdx | 2 +- api_docs/embeddable.devdocs.json | 107 - api_docs/embeddable.mdx | 4 +- 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_annotation_listing.mdx | 2 +- api_docs/event_log.mdx | 2 +- api_docs/exploratory_view.mdx | 2 +- api_docs/expression_error.mdx | 2 +- api_docs/expression_gauge.mdx | 2 +- api_docs/expression_heatmap.mdx | 2 +- api_docs/expression_image.mdx | 2 +- api_docs/expression_legacy_metric_vis.mdx | 2 +- api_docs/expression_metric.mdx | 2 +- api_docs/expression_metric_vis.mdx | 2 +- api_docs/expression_partition_vis.mdx | 2 +- api_docs/expression_repeat_image.mdx | 2 +- api_docs/expression_reveal_image.mdx | 2 +- api_docs/expression_shape.mdx | 2 +- api_docs/expression_tagcloud.mdx | 2 +- api_docs/expression_x_y.mdx | 2 +- api_docs/expressions.mdx | 2 +- api_docs/features.mdx | 2 +- api_docs/field_formats.mdx | 2 +- api_docs/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/ingest_pipelines.mdx | 2 +- api_docs/inspector.mdx | 2 +- api_docs/interactive_setup.mdx | 2 +- api_docs/kbn_ace.mdx | 2 +- api_docs/kbn_actions_types.mdx | 2 +- api_docs/kbn_aiops_components.mdx | 2 +- api_docs/kbn_aiops_utils.mdx | 2 +- .../kbn_alerting_api_integration_helpers.mdx | 2 +- api_docs/kbn_alerting_state_types.mdx | 2 +- api_docs/kbn_alerting_types.mdx | 2 +- api_docs/kbn_alerts_as_data_utils.mdx | 2 +- api_docs/kbn_alerts_ui_shared.mdx | 2 +- api_docs/kbn_analytics.mdx | 2 +- api_docs/kbn_analytics_client.mdx | 2 +- api_docs/kbn_analytics_collection_utils.mdx | 2 +- ..._analytics_shippers_elastic_v3_browser.mdx | 2 +- ...n_analytics_shippers_elastic_v3_common.mdx | 2 +- ...n_analytics_shippers_elastic_v3_server.mdx | 2 +- api_docs/kbn_analytics_shippers_fullstory.mdx | 2 +- api_docs/kbn_analytics_shippers_gainsight.mdx | 2 +- api_docs/kbn_apm_config_loader.mdx | 2 +- api_docs/kbn_apm_synthtrace.mdx | 2 +- api_docs/kbn_apm_synthtrace_client.mdx | 2 +- api_docs/kbn_apm_utils.mdx | 2 +- api_docs/kbn_axe_config.mdx | 2 +- api_docs/kbn_bfetch_error.mdx | 2 +- api_docs/kbn_calculate_auto.mdx | 2 +- .../kbn_calculate_width_from_char_count.mdx | 2 +- api_docs/kbn_cases_components.mdx | 2 +- api_docs/kbn_cell_actions.mdx | 2 +- api_docs/kbn_chart_expressions_common.mdx | 2 +- api_docs/kbn_chart_icons.mdx | 2 +- api_docs/kbn_ci_stats_core.mdx | 2 +- api_docs/kbn_ci_stats_performance_metrics.mdx | 2 +- api_docs/kbn_ci_stats_reporter.mdx | 2 +- api_docs/kbn_cli_dev_mode.mdx | 2 +- api_docs/kbn_code_editor.mdx | 2 +- api_docs/kbn_code_owners.mdx | 2 +- api_docs/kbn_coloring.mdx | 2 +- api_docs/kbn_config.mdx | 2 +- api_docs/kbn_config_mocks.mdx | 2 +- api_docs/kbn_config_schema.mdx | 2 +- .../kbn_content_management_content_editor.mdx | 2 +- ...tent_management_tabbed_table_list_view.mdx | 2 +- ...kbn_content_management_table_list_view.mdx | 2 +- ...tent_management_table_list_view_common.mdx | 2 +- ...ntent_management_table_list_view_table.mdx | 2 +- api_docs/kbn_content_management_utils.mdx | 2 +- api_docs/kbn_core_analytics_browser.mdx | 2 +- .../kbn_core_analytics_browser_internal.mdx | 2 +- api_docs/kbn_core_analytics_browser_mocks.mdx | 2 +- api_docs/kbn_core_analytics_server.mdx | 2 +- .../kbn_core_analytics_server_internal.mdx | 2 +- api_docs/kbn_core_analytics_server_mocks.mdx | 2 +- api_docs/kbn_core_application_browser.mdx | 2 +- .../kbn_core_application_browser_internal.mdx | 2 +- .../kbn_core_application_browser_mocks.mdx | 2 +- api_docs/kbn_core_application_common.mdx | 2 +- api_docs/kbn_core_apps_browser_internal.mdx | 2 +- api_docs/kbn_core_apps_browser_mocks.mdx | 2 +- api_docs/kbn_core_apps_server_internal.mdx | 2 +- api_docs/kbn_core_base_browser_mocks.mdx | 2 +- api_docs/kbn_core_base_common.mdx | 2 +- api_docs/kbn_core_base_server_internal.mdx | 2 +- api_docs/kbn_core_base_server_mocks.mdx | 2 +- .../kbn_core_capabilities_browser_mocks.mdx | 2 +- api_docs/kbn_core_capabilities_common.mdx | 2 +- api_docs/kbn_core_capabilities_server.mdx | 2 +- .../kbn_core_capabilities_server_mocks.mdx | 2 +- api_docs/kbn_core_chrome_browser.mdx | 2 +- api_docs/kbn_core_chrome_browser_mocks.mdx | 2 +- api_docs/kbn_core_config_server_internal.mdx | 2 +- api_docs/kbn_core_custom_branding_browser.mdx | 2 +- ..._core_custom_branding_browser_internal.mdx | 2 +- ...kbn_core_custom_branding_browser_mocks.mdx | 2 +- api_docs/kbn_core_custom_branding_common.mdx | 2 +- api_docs/kbn_core_custom_branding_server.mdx | 2 +- ...n_core_custom_branding_server_internal.mdx | 2 +- .../kbn_core_custom_branding_server_mocks.mdx | 2 +- api_docs/kbn_core_deprecations_browser.mdx | 2 +- ...kbn_core_deprecations_browser_internal.mdx | 2 +- .../kbn_core_deprecations_browser_mocks.mdx | 2 +- api_docs/kbn_core_deprecations_common.mdx | 2 +- api_docs/kbn_core_deprecations_server.mdx | 2 +- .../kbn_core_deprecations_server_internal.mdx | 2 +- .../kbn_core_deprecations_server_mocks.mdx | 2 +- api_docs/kbn_core_doc_links_browser.mdx | 2 +- api_docs/kbn_core_doc_links_browser_mocks.mdx | 2 +- api_docs/kbn_core_doc_links_server.mdx | 2 +- api_docs/kbn_core_doc_links_server_mocks.mdx | 2 +- ...e_elasticsearch_client_server_internal.mdx | 2 +- ...core_elasticsearch_client_server_mocks.mdx | 2 +- api_docs/kbn_core_elasticsearch_server.mdx | 2 +- ...kbn_core_elasticsearch_server_internal.mdx | 2 +- .../kbn_core_elasticsearch_server_mocks.mdx | 2 +- .../kbn_core_environment_server_internal.mdx | 2 +- .../kbn_core_environment_server_mocks.mdx | 2 +- .../kbn_core_execution_context_browser.mdx | 2 +- ...ore_execution_context_browser_internal.mdx | 2 +- ...n_core_execution_context_browser_mocks.mdx | 2 +- .../kbn_core_execution_context_common.mdx | 2 +- .../kbn_core_execution_context_server.mdx | 2 +- ...core_execution_context_server_internal.mdx | 2 +- ...bn_core_execution_context_server_mocks.mdx | 2 +- api_docs/kbn_core_fatal_errors_browser.mdx | 2 +- .../kbn_core_fatal_errors_browser_mocks.mdx | 2 +- api_docs/kbn_core_http_browser.mdx | 2 +- api_docs/kbn_core_http_browser_internal.mdx | 2 +- api_docs/kbn_core_http_browser_mocks.mdx | 2 +- api_docs/kbn_core_http_common.mdx | 2 +- .../kbn_core_http_context_server_mocks.mdx | 2 +- ...re_http_request_handler_context_server.mdx | 2 +- api_docs/kbn_core_http_resources_server.mdx | 2 +- ...bn_core_http_resources_server_internal.mdx | 2 +- .../kbn_core_http_resources_server_mocks.mdx | 2 +- .../kbn_core_http_router_server_internal.mdx | 2 +- .../kbn_core_http_router_server_mocks.mdx | 2 +- api_docs/kbn_core_http_server.mdx | 2 +- api_docs/kbn_core_http_server_internal.mdx | 2 +- api_docs/kbn_core_http_server_mocks.mdx | 2 +- api_docs/kbn_core_i18n_browser.mdx | 2 +- api_docs/kbn_core_i18n_browser_mocks.mdx | 2 +- api_docs/kbn_core_i18n_server.mdx | 2 +- api_docs/kbn_core_i18n_server_internal.mdx | 2 +- api_docs/kbn_core_i18n_server_mocks.mdx | 2 +- ...n_core_injected_metadata_browser_mocks.mdx | 2 +- ...kbn_core_integrations_browser_internal.mdx | 2 +- .../kbn_core_integrations_browser_mocks.mdx | 2 +- api_docs/kbn_core_lifecycle_browser.mdx | 2 +- api_docs/kbn_core_lifecycle_browser_mocks.mdx | 2 +- api_docs/kbn_core_lifecycle_server.mdx | 2 +- api_docs/kbn_core_lifecycle_server_mocks.mdx | 2 +- api_docs/kbn_core_logging_browser_mocks.mdx | 2 +- api_docs/kbn_core_logging_common_internal.mdx | 2 +- api_docs/kbn_core_logging_server.mdx | 2 +- api_docs/kbn_core_logging_server_internal.mdx | 2 +- api_docs/kbn_core_logging_server_mocks.mdx | 2 +- ...ore_metrics_collectors_server_internal.mdx | 2 +- ...n_core_metrics_collectors_server_mocks.mdx | 2 +- api_docs/kbn_core_metrics_server.mdx | 2 +- api_docs/kbn_core_metrics_server_internal.mdx | 2 +- api_docs/kbn_core_metrics_server_mocks.mdx | 2 +- api_docs/kbn_core_mount_utils_browser.mdx | 2 +- api_docs/kbn_core_node_server.mdx | 2 +- api_docs/kbn_core_node_server_internal.mdx | 2 +- api_docs/kbn_core_node_server_mocks.mdx | 2 +- api_docs/kbn_core_notifications_browser.mdx | 2 +- ...bn_core_notifications_browser_internal.mdx | 2 +- .../kbn_core_notifications_browser_mocks.mdx | 2 +- api_docs/kbn_core_overlays_browser.mdx | 2 +- .../kbn_core_overlays_browser_internal.mdx | 2 +- api_docs/kbn_core_overlays_browser_mocks.mdx | 2 +- api_docs/kbn_core_plugins_browser.mdx | 2 +- api_docs/kbn_core_plugins_browser_mocks.mdx | 2 +- .../kbn_core_plugins_contracts_browser.mdx | 2 +- .../kbn_core_plugins_contracts_server.mdx | 2 +- api_docs/kbn_core_plugins_server.mdx | 2 +- api_docs/kbn_core_plugins_server_mocks.mdx | 2 +- api_docs/kbn_core_preboot_server.mdx | 2 +- api_docs/kbn_core_preboot_server_mocks.mdx | 2 +- api_docs/kbn_core_rendering_browser_mocks.mdx | 2 +- .../kbn_core_rendering_server_internal.mdx | 2 +- api_docs/kbn_core_rendering_server_mocks.mdx | 2 +- api_docs/kbn_core_root_server_internal.mdx | 2 +- .../kbn_core_saved_objects_api_browser.mdx | 2 +- .../kbn_core_saved_objects_api_server.mdx | 2 +- ...bn_core_saved_objects_api_server_mocks.mdx | 2 +- ...ore_saved_objects_base_server_internal.mdx | 2 +- ...n_core_saved_objects_base_server_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_browser.mdx | 2 +- ...bn_core_saved_objects_browser_internal.mdx | 2 +- .../kbn_core_saved_objects_browser_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_common.mdx | 2 +- ..._objects_import_export_server_internal.mdx | 2 +- ...ved_objects_import_export_server_mocks.mdx | 2 +- ...aved_objects_migration_server_internal.mdx | 2 +- ...e_saved_objects_migration_server_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_server.mdx | 2 +- ...kbn_core_saved_objects_server_internal.mdx | 2 +- .../kbn_core_saved_objects_server_mocks.mdx | 2 +- .../kbn_core_saved_objects_utils_server.mdx | 2 +- api_docs/kbn_core_status_common.mdx | 2 +- api_docs/kbn_core_status_common_internal.mdx | 2 +- api_docs/kbn_core_status_server.mdx | 2 +- api_docs/kbn_core_status_server_internal.mdx | 2 +- api_docs/kbn_core_status_server_mocks.mdx | 2 +- ...core_test_helpers_deprecations_getters.mdx | 2 +- ...n_core_test_helpers_http_setup_browser.mdx | 2 +- api_docs/kbn_core_test_helpers_kbn_server.mdx | 2 +- .../kbn_core_test_helpers_model_versions.mdx | 2 +- ...n_core_test_helpers_so_type_serializer.mdx | 2 +- api_docs/kbn_core_test_helpers_test_utils.mdx | 2 +- api_docs/kbn_core_theme_browser.mdx | 2 +- api_docs/kbn_core_theme_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_browser.mdx | 2 +- .../kbn_core_ui_settings_browser_internal.mdx | 2 +- .../kbn_core_ui_settings_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_common.mdx | 2 +- api_docs/kbn_core_ui_settings_server.mdx | 2 +- .../kbn_core_ui_settings_server_internal.mdx | 2 +- .../kbn_core_ui_settings_server_mocks.mdx | 2 +- api_docs/kbn_core_usage_data_server.mdx | 2 +- .../kbn_core_usage_data_server_internal.mdx | 2 +- api_docs/kbn_core_usage_data_server_mocks.mdx | 2 +- api_docs/kbn_core_user_settings_server.mdx | 2 +- ...kbn_core_user_settings_server_internal.mdx | 2 +- .../kbn_core_user_settings_server_mocks.mdx | 2 +- api_docs/kbn_crypto.mdx | 2 +- api_docs/kbn_crypto_browser.mdx | 2 +- api_docs/kbn_custom_icons.mdx | 2 +- api_docs/kbn_custom_integrations.mdx | 2 +- api_docs/kbn_cypress_config.mdx | 2 +- api_docs/kbn_data_service.mdx | 2 +- api_docs/kbn_datemath.mdx | 2 +- api_docs/kbn_deeplinks_analytics.mdx | 2 +- api_docs/kbn_deeplinks_devtools.mdx | 2 +- api_docs/kbn_deeplinks_management.mdx | 2 +- api_docs/kbn_deeplinks_ml.mdx | 2 +- api_docs/kbn_deeplinks_observability.mdx | 2 +- api_docs/kbn_deeplinks_search.mdx | 2 +- api_docs/kbn_default_nav_analytics.mdx | 2 +- api_docs/kbn_default_nav_devtools.mdx | 2 +- api_docs/kbn_default_nav_management.mdx | 2 +- api_docs/kbn_default_nav_ml.mdx | 2 +- api_docs/kbn_dev_cli_errors.mdx | 2 +- api_docs/kbn_dev_cli_runner.mdx | 2 +- api_docs/kbn_dev_proc_runner.mdx | 2 +- api_docs/kbn_dev_utils.mdx | 2 +- api_docs/kbn_discover_utils.mdx | 2 +- api_docs/kbn_doc_links.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_elastic_agent_utils.mdx | 2 +- api_docs/kbn_elastic_assistant.mdx | 2 +- api_docs/kbn_elastic_assistant_common.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_event_annotation_common.mdx | 2 +- api_docs/kbn_event_annotation_components.mdx | 2 +- api_docs/kbn_expandable_flyout.mdx | 2 +- api_docs/kbn_field_types.mdx | 2 +- api_docs/kbn_field_utils.mdx | 2 +- api_docs/kbn_find_used_node_modules.mdx | 2 +- .../kbn_ftr_common_functional_services.mdx | 2 +- ...common_functional_ui_services.devdocs.json | 10780 +++++++++++++++- .../kbn_ftr_common_functional_ui_services.mdx | 13 +- api_docs/kbn_generate.mdx | 2 +- api_docs/kbn_generate_console_definitions.mdx | 2 +- api_docs/kbn_generate_csv.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_infra_forge.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_lens_embeddable_utils.mdx | 2 +- api_docs/kbn_lens_formula_docs.mdx | 2 +- api_docs/kbn_logging.mdx | 2 +- api_docs/kbn_logging_mocks.mdx | 2 +- api_docs/kbn_managed_vscode_config.mdx | 2 +- api_docs/kbn_management_cards_navigation.mdx | 2 +- .../kbn_management_settings_application.mdx | 2 +- ...ent_settings_components_field_category.mdx | 2 +- ...gement_settings_components_field_input.mdx | 2 +- ...nagement_settings_components_field_row.mdx | 2 +- ...bn_management_settings_components_form.mdx | 2 +- ...n_management_settings_field_definition.mdx | 2 +- api_docs/kbn_management_settings_ids.mdx | 2 +- ...n_management_settings_section_registry.mdx | 2 +- api_docs/kbn_management_settings_types.mdx | 2 +- .../kbn_management_settings_utilities.mdx | 2 +- api_docs/kbn_management_storybook_config.mdx | 2 +- api_docs/kbn_mapbox_gl.mdx | 2 +- api_docs/kbn_maps_vector_tile_utils.mdx | 2 +- api_docs/kbn_ml_agg_utils.mdx | 2 +- api_docs/kbn_ml_anomaly_utils.mdx | 2 +- api_docs/kbn_ml_category_validator.mdx | 2 +- api_docs/kbn_ml_chi2test.mdx | 2 +- .../kbn_ml_data_frame_analytics_utils.mdx | 2 +- api_docs/kbn_ml_data_grid.mdx | 2 +- api_docs/kbn_ml_date_picker.mdx | 2 +- api_docs/kbn_ml_date_utils.mdx | 2 +- api_docs/kbn_ml_error_utils.mdx | 2 +- api_docs/kbn_ml_in_memory_table.mdx | 2 +- api_docs/kbn_ml_is_defined.mdx | 2 +- api_docs/kbn_ml_is_populated_object.mdx | 2 +- api_docs/kbn_ml_kibana_theme.mdx | 2 +- api_docs/kbn_ml_local_storage.mdx | 2 +- api_docs/kbn_ml_nested_property.mdx | 2 +- api_docs/kbn_ml_number_utils.mdx | 2 +- api_docs/kbn_ml_query_utils.mdx | 2 +- api_docs/kbn_ml_random_sampler_utils.mdx | 2 +- api_docs/kbn_ml_route_utils.mdx | 2 +- api_docs/kbn_ml_runtime_field_utils.mdx | 2 +- api_docs/kbn_ml_string_hash.mdx | 2 +- api_docs/kbn_ml_trained_models_utils.mdx | 2 +- api_docs/kbn_ml_ui_actions.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 +- .../kbn_observability_alerting_test_data.mdx | 2 +- ...ility_get_padded_alert_time_range_util.mdx | 2 +- api_docs/kbn_openapi_bundler.mdx | 2 +- api_docs/kbn_openapi_generator.mdx | 2 +- api_docs/kbn_optimizer.mdx | 2 +- api_docs/kbn_optimizer_webpack_helpers.mdx | 2 +- api_docs/kbn_osquery_io_ts_types.mdx | 2 +- api_docs/kbn_panel_loader.mdx | 2 +- ..._performance_testing_dataset_extractor.mdx | 2 +- api_docs/kbn_plugin_generator.mdx | 2 +- api_docs/kbn_plugin_helpers.mdx | 2 +- api_docs/kbn_profiling_utils.mdx | 2 +- api_docs/kbn_random_sampling.mdx | 2 +- api_docs/kbn_react_field.mdx | 2 +- api_docs/kbn_react_kibana_context_common.mdx | 2 +- api_docs/kbn_react_kibana_context_render.mdx | 2 +- api_docs/kbn_react_kibana_context_root.mdx | 2 +- api_docs/kbn_react_kibana_context_styled.mdx | 2 +- api_docs/kbn_react_kibana_context_theme.mdx | 2 +- api_docs/kbn_react_kibana_mount.mdx | 2 +- api_docs/kbn_repo_file_maps.mdx | 2 +- api_docs/kbn_repo_linter.mdx | 2 +- api_docs/kbn_repo_path.mdx | 2 +- api_docs/kbn_repo_source_classifier.mdx | 2 +- api_docs/kbn_reporting_common.mdx | 2 +- api_docs/kbn_reporting_export_types_csv.mdx | 2 +- .../kbn_reporting_export_types_csv_common.mdx | 2 +- api_docs/kbn_reporting_export_types_pdf.mdx | 2 +- .../kbn_reporting_export_types_pdf_common.mdx | 2 +- api_docs/kbn_reporting_export_types_png.mdx | 2 +- .../kbn_reporting_export_types_png_common.mdx | 2 +- api_docs/kbn_reporting_mocks_server.mdx | 2 +- api_docs/kbn_reporting_public.mdx | 2 +- api_docs/kbn_reporting_server.mdx | 2 +- api_docs/kbn_resizable_layout.mdx | 2 +- api_docs/kbn_rison.mdx | 2 +- api_docs/kbn_router_utils.mdx | 2 +- api_docs/kbn_rrule.mdx | 2 +- api_docs/kbn_rule_data_utils.mdx | 2 +- api_docs/kbn_saved_objects_settings.mdx | 2 +- api_docs/kbn_search_api_panels.mdx | 2 +- api_docs/kbn_search_connectors.mdx | 2 +- api_docs/kbn_search_errors.mdx | 2 +- api_docs/kbn_search_index_documents.mdx | 2 +- api_docs/kbn_search_response_warnings.mdx | 2 +- api_docs/kbn_security_plugin_types_common.mdx | 2 +- api_docs/kbn_security_plugin_types_public.mdx | 2 +- api_docs/kbn_security_plugin_types_server.mdx | 2 +- api_docs/kbn_security_solution_features.mdx | 2 +- api_docs/kbn_security_solution_navigation.mdx | 2 +- api_docs/kbn_security_solution_side_nav.mdx | 2 +- ...kbn_security_solution_storybook_config.mdx | 2 +- .../kbn_securitysolution_autocomplete.mdx | 2 +- api_docs/kbn_securitysolution_data_table.mdx | 2 +- api_docs/kbn_securitysolution_ecs.mdx | 2 +- api_docs/kbn_securitysolution_es_utils.mdx | 2 +- ...ritysolution_exception_list_components.mdx | 2 +- api_docs/kbn_securitysolution_grouping.mdx | 2 +- api_docs/kbn_securitysolution_hook_utils.mdx | 2 +- ..._securitysolution_io_ts_alerting_types.mdx | 2 +- .../kbn_securitysolution_io_ts_list_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_utils.mdx | 2 +- api_docs/kbn_securitysolution_list_api.mdx | 2 +- .../kbn_securitysolution_list_constants.mdx | 2 +- api_docs/kbn_securitysolution_list_hooks.mdx | 2 +- api_docs/kbn_securitysolution_list_utils.mdx | 2 +- api_docs/kbn_securitysolution_rules.mdx | 2 +- api_docs/kbn_securitysolution_t_grid.mdx | 2 +- api_docs/kbn_securitysolution_utils.mdx | 2 +- api_docs/kbn_server_http_tools.mdx | 2 +- api_docs/kbn_server_route_repository.mdx | 2 +- api_docs/kbn_serverless_common_settings.mdx | 2 +- .../kbn_serverless_observability_settings.mdx | 2 +- api_docs/kbn_serverless_project_switcher.mdx | 2 +- api_docs/kbn_serverless_search_settings.mdx | 2 +- api_docs/kbn_serverless_security_settings.mdx | 2 +- api_docs/kbn_serverless_storybook_config.mdx | 2 +- api_docs/kbn_shared_svg.mdx | 2 +- api_docs/kbn_shared_ux_avatar_solution.mdx | 2 +- .../kbn_shared_ux_button_exit_full_screen.mdx | 2 +- api_docs/kbn_shared_ux_button_toolbar.mdx | 2 +- api_docs/kbn_shared_ux_card_no_data.mdx | 2 +- api_docs/kbn_shared_ux_card_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_chrome_navigation.mdx | 2 +- api_docs/kbn_shared_ux_error_boundary.mdx | 2 +- api_docs/kbn_shared_ux_file_context.mdx | 2 +- api_docs/kbn_shared_ux_file_image.mdx | 2 +- api_docs/kbn_shared_ux_file_image_mocks.mdx | 2 +- api_docs/kbn_shared_ux_file_mocks.mdx | 2 +- api_docs/kbn_shared_ux_file_picker.mdx | 2 +- api_docs/kbn_shared_ux_file_types.mdx | 2 +- api_docs/kbn_shared_ux_file_upload.mdx | 2 +- api_docs/kbn_shared_ux_file_util.mdx | 2 +- api_docs/kbn_shared_ux_link_redirect_app.mdx | 2 +- .../kbn_shared_ux_link_redirect_app_mocks.mdx | 2 +- api_docs/kbn_shared_ux_markdown.mdx | 2 +- api_docs/kbn_shared_ux_markdown_mocks.mdx | 2 +- .../kbn_shared_ux_page_analytics_no_data.mdx | 2 +- ...shared_ux_page_analytics_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_page_kibana_no_data.mdx | 2 +- ...bn_shared_ux_page_kibana_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_page_kibana_template.mdx | 2 +- ...n_shared_ux_page_kibana_template_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_no_data.mdx | 2 +- .../kbn_shared_ux_page_no_data_config.mdx | 2 +- ...bn_shared_ux_page_no_data_config_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_solution_nav.mdx | 2 +- .../kbn_shared_ux_prompt_no_data_views.mdx | 2 +- ...n_shared_ux_prompt_no_data_views_mocks.mdx | 2 +- api_docs/kbn_shared_ux_prompt_not_found.mdx | 2 +- api_docs/kbn_shared_ux_router.mdx | 2 +- api_docs/kbn_shared_ux_router_mocks.mdx | 2 +- api_docs/kbn_shared_ux_storybook_config.mdx | 2 +- api_docs/kbn_shared_ux_storybook_mock.mdx | 2 +- api_docs/kbn_shared_ux_utility.mdx | 2 +- 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_text_based_editor.mdx | 2 +- api_docs/kbn_tooling_log.mdx | 2 +- api_docs/kbn_triggers_actions_ui_types.mdx | 2 +- api_docs/kbn_ts_projects.mdx | 2 +- api_docs/kbn_typed_react_router_config.mdx | 2 +- api_docs/kbn_ui_actions_browser.mdx | 2 +- api_docs/kbn_ui_shared_deps_src.mdx | 2 +- api_docs/kbn_ui_theme.mdx | 2 +- api_docs/kbn_unified_data_table.mdx | 2 +- api_docs/kbn_unified_doc_viewer.mdx | 2 +- api_docs/kbn_unified_field_list.mdx | 2 +- api_docs/kbn_unsaved_changes_badge.mdx | 2 +- api_docs/kbn_url_state.mdx | 2 +- api_docs/kbn_use_tracked_promise.mdx | 2 +- api_docs/kbn_user_profile_components.mdx | 2 +- api_docs/kbn_utility_types.mdx | 2 +- api_docs/kbn_utility_types_jest.mdx | 2 +- api_docs/kbn_utils.mdx | 2 +- api_docs/kbn_visualization_ui_components.mdx | 2 +- api_docs/kbn_visualization_utils.mdx | 2 +- api_docs/kbn_xstate_utils.mdx | 2 +- api_docs/kbn_yarn_lock_validator.mdx | 2 +- api_docs/kbn_zod_helpers.mdx | 2 +- api_docs/kibana_overview.mdx | 2 +- api_docs/kibana_react.mdx | 2 +- api_docs/kibana_utils.mdx | 2 +- api_docs/kubernetes_security.mdx | 2 +- api_docs/lens.mdx | 2 +- api_docs/license_api_guard.mdx | 2 +- api_docs/license_management.mdx | 2 +- api_docs/licensing.mdx | 2 +- api_docs/links.mdx | 2 +- api_docs/lists.mdx | 2 +- api_docs/log_explorer.mdx | 2 +- api_docs/logs_shared.mdx | 2 +- api_docs/management.mdx | 2 +- api_docs/maps.mdx | 2 +- api_docs/maps_ems.mdx | 2 +- api_docs/metrics_data_access.mdx | 2 +- api_docs/ml.mdx | 2 +- api_docs/mock_idp_plugin.mdx | 2 +- api_docs/monitoring.mdx | 2 +- api_docs/monitoring_collection.mdx | 2 +- api_docs/navigation.mdx | 2 +- api_docs/newsfeed.mdx | 2 +- api_docs/no_data_page.mdx | 2 +- api_docs/notifications.mdx | 2 +- api_docs/observability.mdx | 2 +- api_docs/observability_a_i_assistant.mdx | 2 +- api_docs/observability_log_explorer.mdx | 2 +- api_docs/observability_onboarding.mdx | 2 +- api_docs/observability_shared.mdx | 2 +- api_docs/osquery.mdx | 2 +- api_docs/painless_lab.mdx | 2 +- api_docs/plugin_directory.mdx | 8 +- api_docs/presentation_util.mdx | 2 +- api_docs/profiling.mdx | 2 +- api_docs/profiling_data_access.mdx | 2 +- api_docs/remote_clusters.mdx | 2 +- api_docs/reporting.mdx | 2 +- api_docs/rollup.mdx | 2 +- api_docs/rule_registry.mdx | 2 +- api_docs/runtime_fields.mdx | 2 +- api_docs/saved_objects.mdx | 2 +- api_docs/saved_objects_finder.mdx | 2 +- api_docs/saved_objects_management.mdx | 2 +- api_docs/saved_objects_tagging.mdx | 2 +- api_docs/saved_objects_tagging_oss.mdx | 2 +- api_docs/saved_search.mdx | 2 +- api_docs/screenshot_mode.mdx | 2 +- api_docs/screenshotting.mdx | 2 +- api_docs/security.mdx | 2 +- api_docs/security_solution.devdocs.json | 14 +- api_docs/security_solution.mdx | 2 +- api_docs/security_solution_ess.mdx | 2 +- api_docs/security_solution_serverless.mdx | 2 +- api_docs/serverless.mdx | 2 +- api_docs/serverless_observability.mdx | 2 +- api_docs/serverless_search.mdx | 2 +- api_docs/session_view.mdx | 2 +- api_docs/share.mdx | 2 +- api_docs/snapshot_restore.mdx | 2 +- api_docs/spaces.mdx | 2 +- api_docs/stack_alerts.mdx | 2 +- api_docs/stack_connectors.mdx | 2 +- api_docs/task_manager.mdx | 2 +- api_docs/telemetry.mdx | 2 +- api_docs/telemetry_collection_manager.mdx | 2 +- api_docs/telemetry_collection_xpack.mdx | 2 +- api_docs/telemetry_management_section.mdx | 2 +- api_docs/text_based_languages.mdx | 2 +- api_docs/threat_intelligence.mdx | 2 +- api_docs/timelines.mdx | 2 +- api_docs/transform.mdx | 2 +- api_docs/triggers_actions_ui.mdx | 2 +- api_docs/ui_actions.mdx | 2 +- api_docs/ui_actions_enhanced.mdx | 2 +- api_docs/unified_doc_viewer.mdx | 2 +- api_docs/unified_histogram.mdx | 2 +- api_docs/unified_search.mdx | 2 +- api_docs/unified_search_autocomplete.mdx | 2 +- api_docs/uptime.mdx | 2 +- api_docs/url_forwarding.mdx | 2 +- api_docs/usage_collection.mdx | 2 +- api_docs/ux.mdx | 2 +- api_docs/vis_default_editor.mdx | 2 +- api_docs/vis_type_gauge.mdx | 2 +- api_docs/vis_type_heatmap.mdx | 2 +- api_docs/vis_type_pie.mdx | 2 +- api_docs/vis_type_table.mdx | 2 +- api_docs/vis_type_timelion.mdx | 2 +- api_docs/vis_type_timeseries.mdx | 2 +- api_docs/vis_type_vega.mdx | 2 +- api_docs/vis_type_vislib.mdx | 2 +- api_docs/vis_type_xy.mdx | 2 +- api_docs/visualizations.mdx | 2 +- 641 files changed, 11420 insertions(+), 789 deletions(-) diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 175c79c8edd8f..9b6fc4e409929 100644 --- a/api_docs/actions.mdx +++ b/api_docs/actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/actions title: "actions" image: https://source.unsplash.com/400x175/?github description: API docs for the actions plugin -date: 2024-01-04 +date: 2024-01-05 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 67938b9ee86c8..08df2353949dd 100644 --- a/api_docs/advanced_settings.mdx +++ b/api_docs/advanced_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/advancedSettings title: "advancedSettings" image: https://source.unsplash.com/400x175/?github description: API docs for the advancedSettings plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/ai_assistant_management_observability.mdx b/api_docs/ai_assistant_management_observability.mdx index 568c9569b3e52..c63f25666847b 100644 --- a/api_docs/ai_assistant_management_observability.mdx +++ b/api_docs/ai_assistant_management_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiAssistantManagementObservability title: "aiAssistantManagementObservability" image: https://source.unsplash.com/400x175/?github description: API docs for the aiAssistantManagementObservability plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiAssistantManagementObservability'] --- import aiAssistantManagementObservabilityObj from './ai_assistant_management_observability.devdocs.json'; diff --git a/api_docs/ai_assistant_management_selection.mdx b/api_docs/ai_assistant_management_selection.mdx index ce9a17f1097c9..b60876a8b2d03 100644 --- a/api_docs/ai_assistant_management_selection.mdx +++ b/api_docs/ai_assistant_management_selection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiAssistantManagementSelection title: "aiAssistantManagementSelection" image: https://source.unsplash.com/400x175/?github description: API docs for the aiAssistantManagementSelection plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiAssistantManagementSelection'] --- import aiAssistantManagementSelectionObj from './ai_assistant_management_selection.devdocs.json'; diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index efe4742f812a6..15fa9e290efd9 100644 --- a/api_docs/aiops.mdx +++ b/api_docs/aiops.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiops title: "aiops" image: https://source.unsplash.com/400x175/?github description: API docs for the aiops plugin -date: 2024-01-04 +date: 2024-01-05 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 5fd8e35e631a9..1c8c1df0579bf 100644 --- a/api_docs/alerting.devdocs.json +++ b/api_docs/alerting.devdocs.json @@ -3573,18 +3573,6 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts" }, - { - "plugin": "stackAlerts", - "path": "x-pack/plugins/stack_alerts/server/rule_types/geo_containment/lib/get_entities_and_generate_alerts.ts" - }, - { - "plugin": "stackAlerts", - "path": "x-pack/plugins/stack_alerts/server/rule_types/geo_containment/executor.ts" - }, - { - "plugin": "stackAlerts", - "path": "x-pack/plugins/stack_alerts/server/rule_types/geo_containment/executor.ts" - }, { "plugin": "synthetics", "path": "x-pack/plugins/synthetics/server/alert_rules/common.ts" diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index e38c25b1345d7..28e361099ddaa 100644 --- a/api_docs/alerting.mdx +++ b/api_docs/alerting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/alerting title: "alerting" image: https://source.unsplash.com/400x175/?github description: API docs for the alerting plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index 97004593fa23a..8a11d4b792ef3 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apm title: "apm" image: https://source.unsplash.com/400x175/?github description: API docs for the apm plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/apm_data_access.mdx b/api_docs/apm_data_access.mdx index 0967e55be0f9f..486a985442330 100644 --- a/api_docs/apm_data_access.mdx +++ b/api_docs/apm_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apmDataAccess title: "apmDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the apmDataAccess plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; diff --git a/api_docs/asset_manager.mdx b/api_docs/asset_manager.mdx index 1cd598a4a0787..3aa9b422a8787 100644 --- a/api_docs/asset_manager.mdx +++ b/api_docs/asset_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/assetManager title: "assetManager" image: https://source.unsplash.com/400x175/?github description: API docs for the assetManager plugin -date: 2024-01-04 +date: 2024-01-05 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 fcfe454cd2efb..933a72cbfb56f 100644 --- a/api_docs/banners.mdx +++ b/api_docs/banners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/banners title: "banners" image: https://source.unsplash.com/400x175/?github description: API docs for the banners plugin -date: 2024-01-04 +date: 2024-01-05 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 42b81bc4929d3..08752e5f08ccf 100644 --- a/api_docs/bfetch.mdx +++ b/api_docs/bfetch.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/bfetch title: "bfetch" image: https://source.unsplash.com/400x175/?github description: API docs for the bfetch plugin -date: 2024-01-04 +date: 2024-01-05 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 569b7601fc2e4..789f5a2e2ad18 100644 --- a/api_docs/canvas.mdx +++ b/api_docs/canvas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/canvas title: "canvas" image: https://source.unsplash.com/400x175/?github description: API docs for the canvas plugin -date: 2024-01-04 +date: 2024-01-05 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 b3d7095d46904..50dee46bbc175 100644 --- a/api_docs/cases.mdx +++ b/api_docs/cases.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cases title: "cases" image: https://source.unsplash.com/400x175/?github description: API docs for the cases plugin -date: 2024-01-04 +date: 2024-01-05 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 1b368f3d45354..904d7ad0d6eae 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/charts title: "charts" image: https://source.unsplash.com/400x175/?github description: API docs for the charts plugin -date: 2024-01-04 +date: 2024-01-05 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 1b9f49f8192d6..de6eb53830687 100644 --- a/api_docs/cloud.mdx +++ b/api_docs/cloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloud title: "cloud" image: https://source.unsplash.com/400x175/?github description: API docs for the cloud plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_data_migration.mdx b/api_docs/cloud_data_migration.mdx index 2f280ede33377..f8df5d8b1d7fc 100644 --- a/api_docs/cloud_data_migration.mdx +++ b/api_docs/cloud_data_migration.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDataMigration title: "cloudDataMigration" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDataMigration plugin -date: 2024-01-04 +date: 2024-01-05 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 e5983addb5003..a3e3efcff6aa3 100644 --- a/api_docs/cloud_defend.mdx +++ b/api_docs/cloud_defend.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDefend title: "cloudDefend" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDefend plugin -date: 2024-01-04 +date: 2024-01-05 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 6974034289448..fa3d2ba58b0c0 100644 --- a/api_docs/cloud_experiments.mdx +++ b/api_docs/cloud_experiments.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudExperiments title: "cloudExperiments" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudExperiments plugin -date: 2024-01-04 +date: 2024-01-05 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 28df21b79fb93..884584688fcdf 100644 --- a/api_docs/cloud_security_posture.mdx +++ b/api_docs/cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudSecurityPosture title: "cloudSecurityPosture" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudSecurityPosture plugin -date: 2024-01-04 +date: 2024-01-05 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 9da7224fcc9dc..1b98439c1e0d5 100644 --- a/api_docs/console.mdx +++ b/api_docs/console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/console title: "console" image: https://source.unsplash.com/400x175/?github description: API docs for the console plugin -date: 2024-01-04 +date: 2024-01-05 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 644a576b9a31b..f9dba5f904033 100644 --- a/api_docs/content_management.mdx +++ b/api_docs/content_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/contentManagement title: "contentManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the contentManagement plugin -date: 2024-01-04 +date: 2024-01-05 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 6d149d7f848d3..6dfd5cfbce66f 100644 --- a/api_docs/controls.mdx +++ b/api_docs/controls.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/controls title: "controls" image: https://source.unsplash.com/400x175/?github description: API docs for the controls plugin -date: 2024-01-04 +date: 2024-01-05 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 6c513a57370b2..066b2ad67f52a 100644 --- a/api_docs/custom_integrations.mdx +++ b/api_docs/custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/customIntegrations title: "customIntegrations" image: https://source.unsplash.com/400x175/?github description: API docs for the customIntegrations plugin -date: 2024-01-04 +date: 2024-01-05 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 8b12f4b0b3825..3aaf1a73398e3 100644 --- a/api_docs/dashboard.mdx +++ b/api_docs/dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboard title: "dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboard plugin -date: 2024-01-04 +date: 2024-01-05 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 ceed4cf64c766..cf0fbc962179b 100644 --- a/api_docs/dashboard_enhanced.mdx +++ b/api_docs/dashboard_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboardEnhanced title: "dashboardEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboardEnhanced plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.mdx b/api_docs/data.mdx index 59da5a91e2c55..908a26ac7ca09 100644 --- a/api_docs/data.mdx +++ b/api_docs/data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data title: "data" image: https://source.unsplash.com/400x175/?github description: API docs for the data plugin -date: 2024-01-04 +date: 2024-01-05 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 57b16fdff130c..e8ed44d73684f 100644 --- a/api_docs/data_query.mdx +++ b/api_docs/data_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-query title: "data.query" image: https://source.unsplash.com/400x175/?github description: API docs for the data.query plugin -date: 2024-01-04 +date: 2024-01-05 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 62cd1bbac7289..14d4d5b20d10d 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-search title: "data.search" image: https://source.unsplash.com/400x175/?github description: API docs for the data.search plugin -date: 2024-01-04 +date: 2024-01-05 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 299c8ec4f418a..482b412c91fcc 100644 --- a/api_docs/data_view_editor.mdx +++ b/api_docs/data_view_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewEditor title: "dataViewEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewEditor plugin -date: 2024-01-04 +date: 2024-01-05 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 426a400c774fd..75fc42ef61f62 100644 --- a/api_docs/data_view_field_editor.mdx +++ b/api_docs/data_view_field_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewFieldEditor title: "dataViewFieldEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewFieldEditor plugin -date: 2024-01-04 +date: 2024-01-05 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 d6991202136d4..6e49fa6c26ff0 100644 --- a/api_docs/data_view_management.mdx +++ b/api_docs/data_view_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewManagement title: "dataViewManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewManagement plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index a0cdcce02e887..f8ac9c9b24ca5 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViews title: "dataViews" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViews plugin -date: 2024-01-04 +date: 2024-01-05 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 bacd296a40466..d27868ff533f8 100644 --- a/api_docs/data_visualizer.mdx +++ b/api_docs/data_visualizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataVisualizer title: "dataVisualizer" image: https://source.unsplash.com/400x175/?github description: API docs for the dataVisualizer plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/dataset_quality.mdx b/api_docs/dataset_quality.mdx index 79815bf40637e..51c627244fdc7 100644 --- a/api_docs/dataset_quality.mdx +++ b/api_docs/dataset_quality.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/datasetQuality title: "datasetQuality" image: https://source.unsplash.com/400x175/?github description: API docs for the datasetQuality plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'datasetQuality'] --- import datasetQualityObj from './dataset_quality.devdocs.json'; diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index 4ce5183771c88..b5602a70aa9a1 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByApi slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-api title: Deprecated API usage by API description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -17,7 +17,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Referencing plugin(s) | Remove By | | ---------------|-----------|-----------| | | ml, stackAlerts | - | -| | ruleRegistry, observability, ml, infra, monitoring, securitySolution, stackAlerts, synthetics, transform, uptime | - | +| | ruleRegistry, observability, ml, infra, monitoring, securitySolution, synthetics, transform, uptime | - | | | share, uiActions, guidedOnboarding, home, serverless, management, spaces, savedObjects, indexManagement, visualizations, dashboard, savedObjectsTagging, expressionXY, lens, expressionMetricVis, expressionGauge, security, alerting, triggersActionsUi, cases, aiops, advancedSettings, licenseManagement, maps, dataVisualizer, ml, exploratoryView, fleet, metricsDataAccess, osquery, ingestPipelines, profiling, apm, expressionImage, expressionMetric, expressionError, expressionRevealImage, expressionRepeatImage, expressionShape, crossClusterReplication, graph, grokdebugger, indexLifecycleManagement, infra, logstash, monitoring, observabilityOnboarding, devTools, painlessLab, remoteClusters, rollup, searchprofiler, newsfeed, securitySolution, snapshotRestore, synthetics, transform, upgradeAssistant, uptime, ux, watcher, cloudDataMigration, console, filesManagement, kibanaOverview, visDefaultEditor, expressionHeatmap, expressionLegacyMetricVis, expressionPartitionVis, expressionTagcloud, visTypeTable, visTypeTimelion, visTypeTimeseries, visTypeVega, visTypeVislib | - | | | encryptedSavedObjects, actions, data, ml, logstash, securitySolution, cloudChat | - | | | actions, ml, savedObjectsTagging, enterpriseSearch | - | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index b55449facaff7..fb5eb527d5e65 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByPlugin slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-plugin title: Deprecated API usage by plugin description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -1419,7 +1419,6 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/es_query/index.ts#:~:text=registerNavigation), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/es_query/index.ts#:~:text=registerNavigation), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/es_query/index.ts#:~:text=registerNavigation), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/es_query/index.ts#:~:text=registerNavigation), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/es_query/index.ts#:~:text=registerNavigation) | - | -| | [get_entities_and_generate_alerts.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/lib/get_entities_and_generate_alerts.ts#:~:text=alertFactory), [executor.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/executor.ts#:~:text=alertFactory), [executor.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/server/rule_types/geo_containment/executor.ts#:~:text=alertFactory) | - | | | [fetch_search_source_query.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_search_source_query.ts#:~:text=fetch), [rule_type.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/server/rule_types/es_query/rule_type.test.ts#:~:text=fetch), [rule_type.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/server/rule_types/es_query/rule_type.test.ts#:~:text=fetch) | - | | | [data_view_select.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/geo_containment/rule_form/data_view_select.tsx#:~:text=indexPatterns), [boundary_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/geo_containment/rule_form/boundary_form.tsx#:~:text=indexPatterns), [boundary_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/geo_containment/rule_form/boundary_form.tsx#:~:text=indexPatterns), [entity_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/geo_containment/rule_form/entity_form.tsx#:~:text=indexPatterns), [entity_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/geo_containment/rule_form/entity_form.tsx#:~:text=indexPatterns) | - | | | [expression.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/threshold/expression.tsx#:~:text=fieldFormats) | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 5c49d1c2111f5..50a0f24b90d18 100644 --- a/api_docs/deprecations_by_team.mdx +++ b/api_docs/deprecations_by_team.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsDueByTeam slug: /kibana-dev-docs/api-meta/deprecations-due-by-team title: Deprecated APIs due to be removed, by team description: Lists the teams that are referencing deprecated APIs with a remove by date. -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index c34d797770737..2eb27ed7d537f 100644 --- a/api_docs/dev_tools.mdx +++ b/api_docs/dev_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/devTools title: "devTools" image: https://source.unsplash.com/400x175/?github description: API docs for the devTools plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index 47dfbf70d346e..0401920b1678b 100644 --- a/api_docs/discover.mdx +++ b/api_docs/discover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discover title: "discover" image: https://source.unsplash.com/400x175/?github description: API docs for the discover plugin -date: 2024-01-04 +date: 2024-01-05 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 caa873b92b456..8d3d79e298cbe 100644 --- a/api_docs/discover_enhanced.mdx +++ b/api_docs/discover_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverEnhanced title: "discoverEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverEnhanced plugin -date: 2024-01-04 +date: 2024-01-05 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 49056bd1bf759..821e5c3e07aa1 100644 --- a/api_docs/ecs_data_quality_dashboard.mdx +++ b/api_docs/ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ecsDataQualityDashboard title: "ecsDataQualityDashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the ecsDataQualityDashboard plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ecsDataQualityDashboard'] --- import ecsDataQualityDashboardObj from './ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/elastic_assistant.mdx b/api_docs/elastic_assistant.mdx index dfb7d99f0c30a..c9b0a42d493d1 100644 --- a/api_docs/elastic_assistant.mdx +++ b/api_docs/elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/elasticAssistant title: "elasticAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the elasticAssistant plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'elasticAssistant'] --- import elasticAssistantObj from './elastic_assistant.devdocs.json'; diff --git a/api_docs/embeddable.devdocs.json b/api_docs/embeddable.devdocs.json index c840f13b2782e..12da9ef05339c 100644 --- a/api_docs/embeddable.devdocs.json +++ b/api_docs/embeddable.devdocs.json @@ -1746,48 +1746,6 @@ "id": "def-public.CustomizePanelAction.Unnamed.$1", "type": "Object", "tags": [], - "label": "overlays", - "description": [], - "signature": [ - { - "pluginId": "@kbn/core-overlays-browser", - "scope": "common", - "docId": "kibKbnCoreOverlaysBrowserPluginApi", - "section": "def-common.OverlayStart", - "text": "OverlayStart" - } - ], - "path": "src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_action.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "embeddable", - "id": "def-public.CustomizePanelAction.Unnamed.$2", - "type": "Object", - "tags": [], - "label": "theme", - "description": [], - "signature": [ - { - "pluginId": "@kbn/core-theme-browser", - "scope": "common", - "docId": "kibKbnCoreThemeBrowserPluginApi", - "section": "def-common.ThemeServiceSetup", - "text": "ThemeServiceSetup" - } - ], - "path": "src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_action.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "embeddable", - "id": "def-public.CustomizePanelAction.Unnamed.$3", - "type": "Object", - "tags": [], "label": "editPanel", "description": [], "signature": [ @@ -1803,71 +1761,6 @@ "deprecated": false, "trackAdoption": false, "isRequired": true - }, - { - "parentPluginId": "embeddable", - "id": "def-public.CustomizePanelAction.Unnamed.$4", - "type": "Array", - "tags": [], - "label": "commonlyUsedRanges", - "description": [], - "signature": [ - "CommonlyUsedRange", - "[] | undefined" - ], - "path": "src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_action.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - }, - { - "parentPluginId": "embeddable", - "id": "def-public.CustomizePanelAction.Unnamed.$5", - "type": "string", - "tags": [], - "label": "dateFormat", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_action.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "embeddable", - "id": "def-public.CustomizePanelAction.isTimeRangeCompatible", - "type": "Function", - "tags": [], - "label": "isTimeRangeCompatible", - "description": [], - "signature": [ - "({ embeddable }: ", - "CustomizePanelActionContext", - ") => boolean" - ], - "path": "src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_action.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "embeddable", - "id": "def-public.CustomizePanelAction.isTimeRangeCompatible.$1", - "type": "Object", - "tags": [], - "label": "{ embeddable }", - "description": [], - "signature": [ - "CustomizePanelActionContext" - ], - "path": "src/plugins/embeddable/public/embeddable_panel/panel_actions/customize_panel_action/customize_panel_action.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true } ], "returnComment": [] diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index 7b0b5851dd68e..76eae0e07b40d 100644 --- a/api_docs/embeddable.mdx +++ b/api_docs/embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddable title: "embeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddable plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddable'] --- import embeddableObj from './embeddable.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kib | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 547 | 1 | 446 | 8 | +| 541 | 1 | 440 | 7 | ## Client diff --git a/api_docs/embeddable_enhanced.mdx b/api_docs/embeddable_enhanced.mdx index 9918254100888..548174d7de37d 100644 --- a/api_docs/embeddable_enhanced.mdx +++ b/api_docs/embeddable_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddableEnhanced title: "embeddableEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddableEnhanced plugin -date: 2024-01-04 +date: 2024-01-05 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 daa6d36a96145..352efa1e656ac 100644 --- a/api_docs/encrypted_saved_objects.mdx +++ b/api_docs/encrypted_saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/encryptedSavedObjects title: "encryptedSavedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the encryptedSavedObjects plugin -date: 2024-01-04 +date: 2024-01-05 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 9474de5f81979..bd1c4bdaf32a6 100644 --- a/api_docs/enterprise_search.mdx +++ b/api_docs/enterprise_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/enterpriseSearch title: "enterpriseSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the enterpriseSearch plugin -date: 2024-01-04 +date: 2024-01-05 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 8320de7c77f9f..6c760ef1be96c 100644 --- a/api_docs/es_ui_shared.mdx +++ b/api_docs/es_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esUiShared title: "esUiShared" image: https://source.unsplash.com/400x175/?github description: API docs for the esUiShared plugin -date: 2024-01-04 +date: 2024-01-05 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 3bc7ef1e9dd79..89cf436a8d03f 100644 --- a/api_docs/event_annotation.mdx +++ b/api_docs/event_annotation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotation title: "eventAnnotation" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotation plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_annotation_listing.mdx b/api_docs/event_annotation_listing.mdx index 4f01a013f6552..4285b824b2865 100644 --- a/api_docs/event_annotation_listing.mdx +++ b/api_docs/event_annotation_listing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotationListing title: "eventAnnotationListing" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotationListing plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotationListing'] --- import eventAnnotationListingObj from './event_annotation_listing.devdocs.json'; diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index dc3c20ed884e9..0f598efcc8e83 100644 --- a/api_docs/event_log.mdx +++ b/api_docs/event_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventLog title: "eventLog" image: https://source.unsplash.com/400x175/?github description: API docs for the eventLog plugin -date: 2024-01-04 +date: 2024-01-05 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 1086207ae79e0..eddcfa9df88b8 100644 --- a/api_docs/exploratory_view.mdx +++ b/api_docs/exploratory_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/exploratoryView title: "exploratoryView" image: https://source.unsplash.com/400x175/?github description: API docs for the exploratoryView plugin -date: 2024-01-04 +date: 2024-01-05 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 ec4f95d64f91b..498a0ab179633 100644 --- a/api_docs/expression_error.mdx +++ b/api_docs/expression_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionError title: "expressionError" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionError plugin -date: 2024-01-04 +date: 2024-01-05 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 fdf929c6a59cb..a58ef618b1988 100644 --- a/api_docs/expression_gauge.mdx +++ b/api_docs/expression_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionGauge title: "expressionGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionGauge plugin -date: 2024-01-04 +date: 2024-01-05 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 38d225279672a..53f605f27359f 100644 --- a/api_docs/expression_heatmap.mdx +++ b/api_docs/expression_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionHeatmap title: "expressionHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionHeatmap plugin -date: 2024-01-04 +date: 2024-01-05 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 27e04629ee41c..8ffa228f761ea 100644 --- a/api_docs/expression_image.mdx +++ b/api_docs/expression_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionImage title: "expressionImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionImage plugin -date: 2024-01-04 +date: 2024-01-05 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 dee6029f3cb90..3339ac65b98da 100644 --- a/api_docs/expression_legacy_metric_vis.mdx +++ b/api_docs/expression_legacy_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionLegacyMetricVis title: "expressionLegacyMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionLegacyMetricVis plugin -date: 2024-01-04 +date: 2024-01-05 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 3096059ad7670..d5053bdf2009c 100644 --- a/api_docs/expression_metric.mdx +++ b/api_docs/expression_metric.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetric title: "expressionMetric" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetric plugin -date: 2024-01-04 +date: 2024-01-05 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 2a20d57c3b137..b4df1088239a3 100644 --- a/api_docs/expression_metric_vis.mdx +++ b/api_docs/expression_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetricVis title: "expressionMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetricVis plugin -date: 2024-01-04 +date: 2024-01-05 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 04ecc8db49661..94b1732f35b83 100644 --- a/api_docs/expression_partition_vis.mdx +++ b/api_docs/expression_partition_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionPartitionVis title: "expressionPartitionVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionPartitionVis plugin -date: 2024-01-04 +date: 2024-01-05 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 b6b0ac67a9cb9..1875640df8d15 100644 --- a/api_docs/expression_repeat_image.mdx +++ b/api_docs/expression_repeat_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRepeatImage title: "expressionRepeatImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRepeatImage plugin -date: 2024-01-04 +date: 2024-01-05 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 e5ab37d98ab79..ac5b410ac3c51 100644 --- a/api_docs/expression_reveal_image.mdx +++ b/api_docs/expression_reveal_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRevealImage title: "expressionRevealImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRevealImage plugin -date: 2024-01-04 +date: 2024-01-05 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 a07ed74186ff5..6c36c1616bbb5 100644 --- a/api_docs/expression_shape.mdx +++ b/api_docs/expression_shape.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionShape title: "expressionShape" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionShape plugin -date: 2024-01-04 +date: 2024-01-05 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 2aa729e87260e..7080b06bdcad3 100644 --- a/api_docs/expression_tagcloud.mdx +++ b/api_docs/expression_tagcloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionTagcloud title: "expressionTagcloud" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionTagcloud plugin -date: 2024-01-04 +date: 2024-01-05 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 0b10fe16fe0f6..9c93e19857dbd 100644 --- a/api_docs/expression_x_y.mdx +++ b/api_docs/expression_x_y.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionXY title: "expressionXY" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionXY plugin -date: 2024-01-04 +date: 2024-01-05 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 b65dc56d93d76..7e6becdb5e3ba 100644 --- a/api_docs/expressions.mdx +++ b/api_docs/expressions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressions title: "expressions" image: https://source.unsplash.com/400x175/?github description: API docs for the expressions plugin -date: 2024-01-04 +date: 2024-01-05 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 9dd6158563493..4e9cddb8f0c95 100644 --- a/api_docs/features.mdx +++ b/api_docs/features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/features title: "features" image: https://source.unsplash.com/400x175/?github description: API docs for the features plugin -date: 2024-01-04 +date: 2024-01-05 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 04e8add44042c..83dc20b9d14f7 100644 --- a/api_docs/field_formats.mdx +++ b/api_docs/field_formats.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldFormats title: "fieldFormats" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldFormats plugin -date: 2024-01-04 +date: 2024-01-05 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 4c98ec2a3d91b..05805282482bc 100644 --- a/api_docs/file_upload.mdx +++ b/api_docs/file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fileUpload title: "fileUpload" image: https://source.unsplash.com/400x175/?github description: API docs for the fileUpload plugin -date: 2024-01-04 +date: 2024-01-05 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 492b70d6729b6..0a106848874eb 100644 --- a/api_docs/files.mdx +++ b/api_docs/files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/files title: "files" image: https://source.unsplash.com/400x175/?github description: API docs for the files plugin -date: 2024-01-04 +date: 2024-01-05 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 34f47024dfd71..c41633bb5c407 100644 --- a/api_docs/files_management.mdx +++ b/api_docs/files_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/filesManagement title: "filesManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the filesManagement plugin -date: 2024-01-04 +date: 2024-01-05 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 71082e7d6c850..d023bf23660db 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fleet title: "fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the fleet plugin -date: 2024-01-04 +date: 2024-01-05 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 f145084416fb0..f1c3cfb571376 100644 --- a/api_docs/global_search.mdx +++ b/api_docs/global_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/globalSearch title: "globalSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the globalSearch plugin -date: 2024-01-04 +date: 2024-01-05 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 69906278ddaf4..67e293184baf7 100644 --- a/api_docs/guided_onboarding.mdx +++ b/api_docs/guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/guidedOnboarding title: "guidedOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the guidedOnboarding plugin -date: 2024-01-04 +date: 2024-01-05 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 24aa7c9926bda..e15635e437a35 100644 --- a/api_docs/home.mdx +++ b/api_docs/home.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/home title: "home" image: https://source.unsplash.com/400x175/?github description: API docs for the home plugin -date: 2024-01-04 +date: 2024-01-05 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 f0e8319806226..269c949a2b510 100644 --- a/api_docs/image_embeddable.mdx +++ b/api_docs/image_embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/imageEmbeddable title: "imageEmbeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the imageEmbeddable plugin -date: 2024-01-04 +date: 2024-01-05 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 e180f0d1641dc..673edd6fc9991 100644 --- a/api_docs/index_lifecycle_management.mdx +++ b/api_docs/index_lifecycle_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexLifecycleManagement title: "indexLifecycleManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexLifecycleManagement plugin -date: 2024-01-04 +date: 2024-01-05 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 5d41b96d012ee..d7047ed6918cb 100644 --- a/api_docs/index_management.mdx +++ b/api_docs/index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexManagement title: "indexManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexManagement plugin -date: 2024-01-04 +date: 2024-01-05 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 f5c39b03aca7f..306a2dd4f1836 100644 --- a/api_docs/infra.mdx +++ b/api_docs/infra.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/infra title: "infra" image: https://source.unsplash.com/400x175/?github description: API docs for the infra plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/ingest_pipelines.mdx b/api_docs/ingest_pipelines.mdx index 6e9aff3bfba06..604704f4a4644 100644 --- a/api_docs/ingest_pipelines.mdx +++ b/api_docs/ingest_pipelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ingestPipelines title: "ingestPipelines" image: https://source.unsplash.com/400x175/?github description: API docs for the ingestPipelines plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ingestPipelines'] --- import ingestPipelinesObj from './ingest_pipelines.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index 03c65d44f35e7..c031e57df940c 100644 --- a/api_docs/inspector.mdx +++ b/api_docs/inspector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inspector title: "inspector" image: https://source.unsplash.com/400x175/?github description: API docs for the inspector plugin -date: 2024-01-04 +date: 2024-01-05 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 0086ac4ce9e8e..2c4f4409c50e6 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/interactiveSetup title: "interactiveSetup" image: https://source.unsplash.com/400x175/?github description: API docs for the interactiveSetup plugin -date: 2024-01-04 +date: 2024-01-05 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 be92db311d961..58c8dd293a89a 100644 --- a/api_docs/kbn_ace.mdx +++ b/api_docs/kbn_ace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ace title: "@kbn/ace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ace plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_actions_types.mdx b/api_docs/kbn_actions_types.mdx index ea6042678334b..67732f9450a66 100644 --- a/api_docs/kbn_actions_types.mdx +++ b/api_docs/kbn_actions_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-actions-types title: "@kbn/actions-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/actions-types plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/actions-types'] --- import kbnActionsTypesObj from './kbn_actions_types.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index 0fceae2c6aa5b..99efb29fa1878 100644 --- a/api_docs/kbn_aiops_components.mdx +++ b/api_docs/kbn_aiops_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-components title: "@kbn/aiops-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-components plugin -date: 2024-01-04 +date: 2024-01-05 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 0c572f58a1412..7c4d66e6a79be 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: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-utils'] --- import kbnAiopsUtilsObj from './kbn_aiops_utils.devdocs.json'; diff --git a/api_docs/kbn_alerting_api_integration_helpers.mdx b/api_docs/kbn_alerting_api_integration_helpers.mdx index 48cae6747c964..5d97cbcef983e 100644 --- a/api_docs/kbn_alerting_api_integration_helpers.mdx +++ b/api_docs/kbn_alerting_api_integration_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-api-integration-helpers title: "@kbn/alerting-api-integration-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-api-integration-helpers plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-api-integration-helpers'] --- import kbnAlertingApiIntegrationHelpersObj from './kbn_alerting_api_integration_helpers.devdocs.json'; diff --git a/api_docs/kbn_alerting_state_types.mdx b/api_docs/kbn_alerting_state_types.mdx index 7109d9c5de8c6..ea31276702c82 100644 --- a/api_docs/kbn_alerting_state_types.mdx +++ b/api_docs/kbn_alerting_state_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-state-types title: "@kbn/alerting-state-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-state-types plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-state-types'] --- import kbnAlertingStateTypesObj from './kbn_alerting_state_types.devdocs.json'; diff --git a/api_docs/kbn_alerting_types.mdx b/api_docs/kbn_alerting_types.mdx index 81baf5ce3dea1..9c0634d2f5fac 100644 --- a/api_docs/kbn_alerting_types.mdx +++ b/api_docs/kbn_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-types title: "@kbn/alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-types plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-types'] --- import kbnAlertingTypesObj from './kbn_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_alerts_as_data_utils.mdx b/api_docs/kbn_alerts_as_data_utils.mdx index 9e2d04708b8dd..d13f7538c6f18 100644 --- a/api_docs/kbn_alerts_as_data_utils.mdx +++ b/api_docs/kbn_alerts_as_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-as-data-utils title: "@kbn/alerts-as-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-as-data-utils plugin -date: 2024-01-04 +date: 2024-01-05 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 b835cdf345430..dd820870f56ae 100644 --- a/api_docs/kbn_alerts_ui_shared.mdx +++ b/api_docs/kbn_alerts_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-ui-shared title: "@kbn/alerts-ui-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-ui-shared plugin -date: 2024-01-04 +date: 2024-01-05 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 bb47843b82e3e..07f4f676b6482 100644 --- a/api_docs/kbn_analytics.mdx +++ b/api_docs/kbn_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics title: "@kbn/analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics plugin -date: 2024-01-04 +date: 2024-01-05 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 3b5f66fe191c9..aa6359d944086 100644 --- a/api_docs/kbn_analytics_client.mdx +++ b/api_docs/kbn_analytics_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-client title: "@kbn/analytics-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-client plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-client'] --- import kbnAnalyticsClientObj from './kbn_analytics_client.devdocs.json'; diff --git a/api_docs/kbn_analytics_collection_utils.mdx b/api_docs/kbn_analytics_collection_utils.mdx index a5ebd4cabb524..26f300afff2f9 100644 --- a/api_docs/kbn_analytics_collection_utils.mdx +++ b/api_docs/kbn_analytics_collection_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-collection-utils title: "@kbn/analytics-collection-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-collection-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-collection-utils'] --- import kbnAnalyticsCollectionUtilsObj from './kbn_analytics_collection_utils.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx index 4ad36ce3266e0..eecc34a7903ac 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-browser title: "@kbn/analytics-shippers-elastic-v3-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 2f441677caed3..12347d76060af 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-common title: "@kbn/analytics-shippers-elastic-v3-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-common plugin -date: 2024-01-04 +date: 2024-01-05 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 6d37607eb3780..6f8daf129a9ad 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-server title: "@kbn/analytics-shippers-elastic-v3-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-server plugin -date: 2024-01-04 +date: 2024-01-05 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 dbf2ed50486ea..4c7a7db8dc103 100644 --- a/api_docs/kbn_analytics_shippers_fullstory.mdx +++ b/api_docs/kbn_analytics_shippers_fullstory.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-fullstory title: "@kbn/analytics-shippers-fullstory" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-fullstory plugin -date: 2024-01-04 +date: 2024-01-05 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 6c2e2085a35e6..67adc5447da8c 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: 2024-01-04 +date: 2024-01-05 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 2e4da0de9fffb..fb2645ed8940b 100644 --- a/api_docs/kbn_apm_config_loader.mdx +++ b/api_docs/kbn_apm_config_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-config-loader title: "@kbn/apm-config-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-config-loader plugin -date: 2024-01-04 +date: 2024-01-05 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 08be197d2f328..c5a2d9d1be71e 100644 --- a/api_docs/kbn_apm_synthtrace.mdx +++ b/api_docs/kbn_apm_synthtrace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace title: "@kbn/apm-synthtrace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace_client.mdx b/api_docs/kbn_apm_synthtrace_client.mdx index 57f76574a6a01..b7e5007d1daef 100644 --- a/api_docs/kbn_apm_synthtrace_client.mdx +++ b/api_docs/kbn_apm_synthtrace_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace-client title: "@kbn/apm-synthtrace-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace-client plugin -date: 2024-01-04 +date: 2024-01-05 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 d4f8acded8bea..19dd1cddbbb54 100644 --- a/api_docs/kbn_apm_utils.mdx +++ b/api_docs/kbn_apm_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-utils title: "@kbn/apm-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-utils plugin -date: 2024-01-04 +date: 2024-01-05 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 691cc29eab2b5..3b1aaa7f5bc1a 100644 --- a/api_docs/kbn_axe_config.mdx +++ b/api_docs/kbn_axe_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-axe-config title: "@kbn/axe-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/axe-config plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_bfetch_error.mdx b/api_docs/kbn_bfetch_error.mdx index 6ffb7d64aa166..95e9ef9d8e2cc 100644 --- a/api_docs/kbn_bfetch_error.mdx +++ b/api_docs/kbn_bfetch_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-bfetch-error title: "@kbn/bfetch-error" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/bfetch-error plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/bfetch-error'] --- import kbnBfetchErrorObj from './kbn_bfetch_error.devdocs.json'; diff --git a/api_docs/kbn_calculate_auto.mdx b/api_docs/kbn_calculate_auto.mdx index bbcb29ede912a..4f9a6ae989578 100644 --- a/api_docs/kbn_calculate_auto.mdx +++ b/api_docs/kbn_calculate_auto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-calculate-auto title: "@kbn/calculate-auto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/calculate-auto plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-auto'] --- import kbnCalculateAutoObj from './kbn_calculate_auto.devdocs.json'; diff --git a/api_docs/kbn_calculate_width_from_char_count.mdx b/api_docs/kbn_calculate_width_from_char_count.mdx index 168799bba2c8b..8a0212183d0e7 100644 --- a/api_docs/kbn_calculate_width_from_char_count.mdx +++ b/api_docs/kbn_calculate_width_from_char_count.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-calculate-width-from-char-count title: "@kbn/calculate-width-from-char-count" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/calculate-width-from-char-count plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-width-from-char-count'] --- import kbnCalculateWidthFromCharCountObj from './kbn_calculate_width_from_char_count.devdocs.json'; diff --git a/api_docs/kbn_cases_components.mdx b/api_docs/kbn_cases_components.mdx index 1cb18fc4b85cf..3ad99c30a2135 100644 --- a/api_docs/kbn_cases_components.mdx +++ b/api_docs/kbn_cases_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cases-components title: "@kbn/cases-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cases-components plugin -date: 2024-01-04 +date: 2024-01-05 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 af7a6aec2f060..5da6071844462 100644 --- a/api_docs/kbn_cell_actions.mdx +++ b/api_docs/kbn_cell_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cell-actions title: "@kbn/cell-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cell-actions plugin -date: 2024-01-04 +date: 2024-01-05 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 8709c69a78d2b..f99acdf51bc1e 100644 --- a/api_docs/kbn_chart_expressions_common.mdx +++ b/api_docs/kbn_chart_expressions_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-expressions-common title: "@kbn/chart-expressions-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-expressions-common plugin -date: 2024-01-04 +date: 2024-01-05 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 f3d78c78a2774..99dfb9291a2c5 100644 --- a/api_docs/kbn_chart_icons.mdx +++ b/api_docs/kbn_chart_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-icons title: "@kbn/chart-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-icons plugin -date: 2024-01-04 +date: 2024-01-05 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 fd14fa1f9cc05..8e4e8dcfeaf16 100644 --- a/api_docs/kbn_ci_stats_core.mdx +++ b/api_docs/kbn_ci_stats_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-core title: "@kbn/ci-stats-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-core plugin -date: 2024-01-04 +date: 2024-01-05 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 c5160318f3046..3c1646598d3c9 100644 --- a/api_docs/kbn_ci_stats_performance_metrics.mdx +++ b/api_docs/kbn_ci_stats_performance_metrics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-performance-metrics title: "@kbn/ci-stats-performance-metrics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-performance-metrics plugin -date: 2024-01-04 +date: 2024-01-05 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 6b5d8e5811c66..9ae2a3c9cf53d 100644 --- a/api_docs/kbn_ci_stats_reporter.mdx +++ b/api_docs/kbn_ci_stats_reporter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-reporter title: "@kbn/ci-stats-reporter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-reporter plugin -date: 2024-01-04 +date: 2024-01-05 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 c25eb3b034f9a..0d428a2b65c4e 100644 --- a/api_docs/kbn_cli_dev_mode.mdx +++ b/api_docs/kbn_cli_dev_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cli-dev-mode title: "@kbn/cli-dev-mode" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cli-dev-mode plugin -date: 2024-01-04 +date: 2024-01-05 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 b1faf78313c5d..c979f6dc50d4f 100644 --- a/api_docs/kbn_code_editor.mdx +++ b/api_docs/kbn_code_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor title: "@kbn/code-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor'] --- import kbnCodeEditorObj from './kbn_code_editor.devdocs.json'; diff --git a/api_docs/kbn_code_owners.mdx b/api_docs/kbn_code_owners.mdx index 45c2f1eec850e..f226a1348df2f 100644 --- a/api_docs/kbn_code_owners.mdx +++ b/api_docs/kbn_code_owners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-owners title: "@kbn/code-owners" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-owners plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-owners'] --- import kbnCodeOwnersObj from './kbn_code_owners.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index 016a50f4eed68..888e0b94e7c94 100644 --- a/api_docs/kbn_coloring.mdx +++ b/api_docs/kbn_coloring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-coloring title: "@kbn/coloring" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/coloring plugin -date: 2024-01-04 +date: 2024-01-05 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 92e2a6e6a98db..ecdf371ddfffd 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config title: "@kbn/config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config plugin -date: 2024-01-04 +date: 2024-01-05 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 538b978f01f67..5e15a806482fd 100644 --- a/api_docs/kbn_config_mocks.mdx +++ b/api_docs/kbn_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-mocks title: "@kbn/config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 7a11d031669b2..e8b490fcaa551 100644 --- a/api_docs/kbn_config_schema.mdx +++ b/api_docs/kbn_config_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-schema title: "@kbn/config-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-schema plugin -date: 2024-01-04 +date: 2024-01-05 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 a01fcd538b274..2080f7a4f5456 100644 --- a/api_docs/kbn_content_management_content_editor.mdx +++ b/api_docs/kbn_content_management_content_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-editor title: "@kbn/content-management-content-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-editor plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-editor'] --- import kbnContentManagementContentEditorObj from './kbn_content_management_content_editor.devdocs.json'; diff --git a/api_docs/kbn_content_management_tabbed_table_list_view.mdx b/api_docs/kbn_content_management_tabbed_table_list_view.mdx index ab99b334698e8..afa1cc531eeca 100644 --- a/api_docs/kbn_content_management_tabbed_table_list_view.mdx +++ b/api_docs/kbn_content_management_tabbed_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-tabbed-table-list-view title: "@kbn/content-management-tabbed-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-tabbed-table-list-view plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-tabbed-table-list-view'] --- import kbnContentManagementTabbedTableListViewObj from './kbn_content_management_tabbed_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view.mdx b/api_docs/kbn_content_management_table_list_view.mdx index ac36b039e2e28..296cdd60739d3 100644 --- a/api_docs/kbn_content_management_table_list_view.mdx +++ b/api_docs/kbn_content_management_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view title: "@kbn/content-management-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view'] --- import kbnContentManagementTableListViewObj from './kbn_content_management_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view_common.mdx b/api_docs/kbn_content_management_table_list_view_common.mdx index ba7e057ea4c5e..295f28d250efb 100644 --- a/api_docs/kbn_content_management_table_list_view_common.mdx +++ b/api_docs/kbn_content_management_table_list_view_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view-common title: "@kbn/content-management-table-list-view-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view-common plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-common'] --- import kbnContentManagementTableListViewCommonObj from './kbn_content_management_table_list_view_common.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view_table.mdx b/api_docs/kbn_content_management_table_list_view_table.mdx index 4eb648daed693..bd4a59931d367 100644 --- a/api_docs/kbn_content_management_table_list_view_table.mdx +++ b/api_docs/kbn_content_management_table_list_view_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view-table title: "@kbn/content-management-table-list-view-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view-table plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-table'] --- import kbnContentManagementTableListViewTableObj from './kbn_content_management_table_list_view_table.devdocs.json'; diff --git a/api_docs/kbn_content_management_utils.mdx b/api_docs/kbn_content_management_utils.mdx index b93c28f3f242f..2334bbea11063 100644 --- a/api_docs/kbn_content_management_utils.mdx +++ b/api_docs/kbn_content_management_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-utils title: "@kbn/content-management-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-utils'] --- import kbnContentManagementUtilsObj from './kbn_content_management_utils.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index 5d321c806dae1..42c9d614c5797 100644 --- a/api_docs/kbn_core_analytics_browser.mdx +++ b/api_docs/kbn_core_analytics_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser title: "@kbn/core-analytics-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 1f543f4bf84ce..153a2c7a9152f 100644 --- a/api_docs/kbn_core_analytics_browser_internal.mdx +++ b/api_docs/kbn_core_analytics_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-internal title: "@kbn/core-analytics-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 2705851553d33..b514f46a767d3 100644 --- a/api_docs/kbn_core_analytics_browser_mocks.mdx +++ b/api_docs/kbn_core_analytics_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-mocks title: "@kbn/core-analytics-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 7c3743c1dbd8c..22a2b868300d7 100644 --- a/api_docs/kbn_core_analytics_server.mdx +++ b/api_docs/kbn_core_analytics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server title: "@kbn/core-analytics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server plugin -date: 2024-01-04 +date: 2024-01-05 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 3e4b93af573ae..8e99ad34f05ad 100644 --- a/api_docs/kbn_core_analytics_server_internal.mdx +++ b/api_docs/kbn_core_analytics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-internal title: "@kbn/core-analytics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 13fddb27bcd44..34dc36645e8d9 100644 --- a/api_docs/kbn_core_analytics_server_mocks.mdx +++ b/api_docs/kbn_core_analytics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-mocks title: "@kbn/core-analytics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 79983ab12c2e4..003b923f10aa1 100644 --- a/api_docs/kbn_core_application_browser.mdx +++ b/api_docs/kbn_core_application_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser title: "@kbn/core-application-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 c96835fd136f4..6286d2cb724ec 100644 --- a/api_docs/kbn_core_application_browser_internal.mdx +++ b/api_docs/kbn_core_application_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-internal title: "@kbn/core-application-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 0d0d8e97c742e..4129c3bcf8444 100644 --- a/api_docs/kbn_core_application_browser_mocks.mdx +++ b/api_docs/kbn_core_application_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-mocks title: "@kbn/core-application-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 8448a8305a7e5..189ddf1305682 100644 --- a/api_docs/kbn_core_application_common.mdx +++ b/api_docs/kbn_core_application_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-common title: "@kbn/core-application-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-common plugin -date: 2024-01-04 +date: 2024-01-05 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 9723b65a44983..c00e06b1d4e53 100644 --- a/api_docs/kbn_core_apps_browser_internal.mdx +++ b/api_docs/kbn_core_apps_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-internal title: "@kbn/core-apps-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 596f3e1409ae3..dfc0190d41a19 100644 --- a/api_docs/kbn_core_apps_browser_mocks.mdx +++ b/api_docs/kbn_core_apps_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-mocks title: "@kbn/core-apps-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 d271d9e001764..9a818b7a9cf70 100644 --- a/api_docs/kbn_core_apps_server_internal.mdx +++ b/api_docs/kbn_core_apps_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-server-internal title: "@kbn/core-apps-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 67397822cc15e..5d983edad908c 100644 --- a/api_docs/kbn_core_base_browser_mocks.mdx +++ b/api_docs/kbn_core_base_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-browser-mocks title: "@kbn/core-base-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 96261af6de97b..96380b2c5e499 100644 --- a/api_docs/kbn_core_base_common.mdx +++ b/api_docs/kbn_core_base_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-common title: "@kbn/core-base-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-common plugin -date: 2024-01-04 +date: 2024-01-05 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 690927a8f239f..10e1fbe8f64d3 100644 --- a/api_docs/kbn_core_base_server_internal.mdx +++ b/api_docs/kbn_core_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-internal title: "@kbn/core-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 acdf0cea09385..8811b252d3a45 100644 --- a/api_docs/kbn_core_base_server_mocks.mdx +++ b/api_docs/kbn_core_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-mocks title: "@kbn/core-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 05311bbc8df07..3e2a93bdaa39c 100644 --- a/api_docs/kbn_core_capabilities_browser_mocks.mdx +++ b/api_docs/kbn_core_capabilities_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-browser-mocks title: "@kbn/core-capabilities-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 b394f4e578b45..a43d1d79f59be 100644 --- a/api_docs/kbn_core_capabilities_common.mdx +++ b/api_docs/kbn_core_capabilities_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-common title: "@kbn/core-capabilities-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-common plugin -date: 2024-01-04 +date: 2024-01-05 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 04e0c62d9deaf..9aecb50d3630b 100644 --- a/api_docs/kbn_core_capabilities_server.mdx +++ b/api_docs/kbn_core_capabilities_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server title: "@kbn/core-capabilities-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server plugin -date: 2024-01-04 +date: 2024-01-05 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 4b249f1bff217..36c6be975a5db 100644 --- a/api_docs/kbn_core_capabilities_server_mocks.mdx +++ b/api_docs/kbn_core_capabilities_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server-mocks title: "@kbn/core-capabilities-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 5e8bdf8c5aa08..6355589137357 100644 --- a/api_docs/kbn_core_chrome_browser.mdx +++ b/api_docs/kbn_core_chrome_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser title: "@kbn/core-chrome-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 02e3a5ec0123f..9b90d0d77d1bc 100644 --- a/api_docs/kbn_core_chrome_browser_mocks.mdx +++ b/api_docs/kbn_core_chrome_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser-mocks title: "@kbn/core-chrome-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 2289372300052..36d73d21f57f4 100644 --- a/api_docs/kbn_core_config_server_internal.mdx +++ b/api_docs/kbn_core_config_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-config-server-internal title: "@kbn/core-config-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-config-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 fb768b7c12d3f..11c405617243b 100644 --- a/api_docs/kbn_core_custom_branding_browser.mdx +++ b/api_docs/kbn_core_custom_branding_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser title: "@kbn/core-custom-branding-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 47066277a2823..cf5f3594cacd5 100644 --- a/api_docs/kbn_core_custom_branding_browser_internal.mdx +++ b/api_docs/kbn_core_custom_branding_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-internal title: "@kbn/core-custom-branding-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 0557c03698a20..5efaad8b4b761 100644 --- a/api_docs/kbn_core_custom_branding_browser_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-mocks title: "@kbn/core-custom-branding-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 e4c2d814ce4ce..c8d037dfb1be0 100644 --- a/api_docs/kbn_core_custom_branding_common.mdx +++ b/api_docs/kbn_core_custom_branding_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-common title: "@kbn/core-custom-branding-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-common plugin -date: 2024-01-04 +date: 2024-01-05 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 47df9f6bd415c..ac3d4fee5471d 100644 --- a/api_docs/kbn_core_custom_branding_server.mdx +++ b/api_docs/kbn_core_custom_branding_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server title: "@kbn/core-custom-branding-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server plugin -date: 2024-01-04 +date: 2024-01-05 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 8f0176938100e..f394f80ac1a44 100644 --- a/api_docs/kbn_core_custom_branding_server_internal.mdx +++ b/api_docs/kbn_core_custom_branding_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-internal title: "@kbn/core-custom-branding-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 5c6ac50845b06..6fa595b3f7ddb 100644 --- a/api_docs/kbn_core_custom_branding_server_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-mocks title: "@kbn/core-custom-branding-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 cb4891afb2a62..4dd8071edb617 100644 --- a/api_docs/kbn_core_deprecations_browser.mdx +++ b/api_docs/kbn_core_deprecations_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser title: "@kbn/core-deprecations-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 2fcebc148f34f..2868afa3f6c57 100644 --- a/api_docs/kbn_core_deprecations_browser_internal.mdx +++ b/api_docs/kbn_core_deprecations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-internal title: "@kbn/core-deprecations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 40c40b888547e..3583323fb993a 100644 --- a/api_docs/kbn_core_deprecations_browser_mocks.mdx +++ b/api_docs/kbn_core_deprecations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-mocks title: "@kbn/core-deprecations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 276dae6fdc910..aa0538b54ed96 100644 --- a/api_docs/kbn_core_deprecations_common.mdx +++ b/api_docs/kbn_core_deprecations_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-common title: "@kbn/core-deprecations-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-common plugin -date: 2024-01-04 +date: 2024-01-05 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 06938c8a2b3d5..66613027f1595 100644 --- a/api_docs/kbn_core_deprecations_server.mdx +++ b/api_docs/kbn_core_deprecations_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server title: "@kbn/core-deprecations-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server plugin -date: 2024-01-04 +date: 2024-01-05 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 096e7236e1524..07f76eadc4a07 100644 --- a/api_docs/kbn_core_deprecations_server_internal.mdx +++ b/api_docs/kbn_core_deprecations_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-internal title: "@kbn/core-deprecations-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 cc44b8b202e8f..c2eedb7775bc5 100644 --- a/api_docs/kbn_core_deprecations_server_mocks.mdx +++ b/api_docs/kbn_core_deprecations_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-mocks title: "@kbn/core-deprecations-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 2f95b164db63d..7476d9890e76d 100644 --- a/api_docs/kbn_core_doc_links_browser.mdx +++ b/api_docs/kbn_core_doc_links_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser title: "@kbn/core-doc-links-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 e001c1a7741c5..ff520667e6286 100644 --- a/api_docs/kbn_core_doc_links_browser_mocks.mdx +++ b/api_docs/kbn_core_doc_links_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser-mocks title: "@kbn/core-doc-links-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 0dd3e339adf53..698406787e33c 100644 --- a/api_docs/kbn_core_doc_links_server.mdx +++ b/api_docs/kbn_core_doc_links_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server title: "@kbn/core-doc-links-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server plugin -date: 2024-01-04 +date: 2024-01-05 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 039d4286527ab..a4bfe1af57f18 100644 --- a/api_docs/kbn_core_doc_links_server_mocks.mdx +++ b/api_docs/kbn_core_doc_links_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server-mocks title: "@kbn/core-doc-links-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 6ae23ebdbc4f2..c6579465e4d94 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-internal title: "@kbn/core-elasticsearch-client-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 84519ae1e6f50..50797c4a70444 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-mocks title: "@kbn/core-elasticsearch-client-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 58dc5db374275..5877335b3b4b6 100644 --- a/api_docs/kbn_core_elasticsearch_server.mdx +++ b/api_docs/kbn_core_elasticsearch_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server title: "@kbn/core-elasticsearch-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server plugin -date: 2024-01-04 +date: 2024-01-05 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 30259cc8ff033..dfd4378709eee 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-internal title: "@kbn/core-elasticsearch-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 fb88fcd87870e..b3194820e611d 100644 --- a/api_docs/kbn_core_elasticsearch_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-mocks title: "@kbn/core-elasticsearch-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 0b45eda63a4d6..9096578c4a869 100644 --- a/api_docs/kbn_core_environment_server_internal.mdx +++ b/api_docs/kbn_core_environment_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-internal title: "@kbn/core-environment-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 68780da325957..d8329ab84c6fd 100644 --- a/api_docs/kbn_core_environment_server_mocks.mdx +++ b/api_docs/kbn_core_environment_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-mocks title: "@kbn/core-environment-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 84acec6f8c4d0..c6051b14b8bb8 100644 --- a/api_docs/kbn_core_execution_context_browser.mdx +++ b/api_docs/kbn_core_execution_context_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser title: "@kbn/core-execution-context-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 6f5cdfc30e9fb..0f4b1d809e2a9 100644 --- a/api_docs/kbn_core_execution_context_browser_internal.mdx +++ b/api_docs/kbn_core_execution_context_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-internal title: "@kbn/core-execution-context-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 dae8f7597fa85..e0335fd19b456 100644 --- a/api_docs/kbn_core_execution_context_browser_mocks.mdx +++ b/api_docs/kbn_core_execution_context_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-mocks title: "@kbn/core-execution-context-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 d3443180f5e37..e34ee98f08541 100644 --- a/api_docs/kbn_core_execution_context_common.mdx +++ b/api_docs/kbn_core_execution_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-common title: "@kbn/core-execution-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-common plugin -date: 2024-01-04 +date: 2024-01-05 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 9bcd85c18be25..a9cd993ef3613 100644 --- a/api_docs/kbn_core_execution_context_server.mdx +++ b/api_docs/kbn_core_execution_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server title: "@kbn/core-execution-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server plugin -date: 2024-01-04 +date: 2024-01-05 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 c55c66060c457..9a092dd212918 100644 --- a/api_docs/kbn_core_execution_context_server_internal.mdx +++ b/api_docs/kbn_core_execution_context_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-internal title: "@kbn/core-execution-context-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 c02aee85f62c2..fe7dfdc0640b1 100644 --- a/api_docs/kbn_core_execution_context_server_mocks.mdx +++ b/api_docs/kbn_core_execution_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-mocks title: "@kbn/core-execution-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 a370ba31b7392..ca637613e3dca 100644 --- a/api_docs/kbn_core_fatal_errors_browser.mdx +++ b/api_docs/kbn_core_fatal_errors_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser title: "@kbn/core-fatal-errors-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 4cd23b56d2049..7bae8c7510fe8 100644 --- a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx +++ b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser-mocks title: "@kbn/core-fatal-errors-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 b1d5fa2f87bf7..c0dc5ef4d8166 100644 --- a/api_docs/kbn_core_http_browser.mdx +++ b/api_docs/kbn_core_http_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser title: "@kbn/core-http-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 95910196e46a0..c4a4931aa224e 100644 --- a/api_docs/kbn_core_http_browser_internal.mdx +++ b/api_docs/kbn_core_http_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-internal title: "@kbn/core-http-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 bf351d6b6045b..d5b59d087d88d 100644 --- a/api_docs/kbn_core_http_browser_mocks.mdx +++ b/api_docs/kbn_core_http_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-mocks title: "@kbn/core-http-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 cf934a82ce8a1..fdaf73a8bdf94 100644 --- a/api_docs/kbn_core_http_common.mdx +++ b/api_docs/kbn_core_http_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-common title: "@kbn/core-http-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-common plugin -date: 2024-01-04 +date: 2024-01-05 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 cf0cc09149fe9..7a13acd3b6ee4 100644 --- a/api_docs/kbn_core_http_context_server_mocks.mdx +++ b/api_docs/kbn_core_http_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-context-server-mocks title: "@kbn/core-http-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-context-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 c843f511ba710..3bc12db9ecfe0 100644 --- a/api_docs/kbn_core_http_request_handler_context_server.mdx +++ b/api_docs/kbn_core_http_request_handler_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-request-handler-context-server title: "@kbn/core-http-request-handler-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-request-handler-context-server plugin -date: 2024-01-04 +date: 2024-01-05 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 9b26b97d0bf25..d6d4afcb46f88 100644 --- a/api_docs/kbn_core_http_resources_server.mdx +++ b/api_docs/kbn_core_http_resources_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server title: "@kbn/core-http-resources-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server plugin -date: 2024-01-04 +date: 2024-01-05 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 3e9098cf3068b..f86eb611844b8 100644 --- a/api_docs/kbn_core_http_resources_server_internal.mdx +++ b/api_docs/kbn_core_http_resources_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-internal title: "@kbn/core-http-resources-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 0f301dc896f4c..fb0b69d74b6c1 100644 --- a/api_docs/kbn_core_http_resources_server_mocks.mdx +++ b/api_docs/kbn_core_http_resources_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-mocks title: "@kbn/core-http-resources-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 4619b1f044320..8717f3484e4d2 100644 --- a/api_docs/kbn_core_http_router_server_internal.mdx +++ b/api_docs/kbn_core_http_router_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-internal title: "@kbn/core-http-router-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 1b0b50082abf7..89196d48aa807 100644 --- a/api_docs/kbn_core_http_router_server_mocks.mdx +++ b/api_docs/kbn_core_http_router_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-mocks title: "@kbn/core-http-router-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 1646c74c42d11..13108de8ed0b6 100644 --- a/api_docs/kbn_core_http_server.mdx +++ b/api_docs/kbn_core_http_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server title: "@kbn/core-http-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server plugin -date: 2024-01-04 +date: 2024-01-05 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 95405dcd06ca7..c79302c665bd3 100644 --- a/api_docs/kbn_core_http_server_internal.mdx +++ b/api_docs/kbn_core_http_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-internal title: "@kbn/core-http-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 d23065a22a01e..5346aa263fbfb 100644 --- a/api_docs/kbn_core_http_server_mocks.mdx +++ b/api_docs/kbn_core_http_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-mocks title: "@kbn/core-http-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 807e09bb6a594..5dc4097c8c4dc 100644 --- a/api_docs/kbn_core_i18n_browser.mdx +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser title: "@kbn/core-i18n-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 20ebff06fbca3..d5bfe62f3f7cd 100644 --- a/api_docs/kbn_core_i18n_browser_mocks.mdx +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks title: "@kbn/core-i18n-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 f56413569351d..a9e8270c39be9 100644 --- a/api_docs/kbn_core_i18n_server.mdx +++ b/api_docs/kbn_core_i18n_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server title: "@kbn/core-i18n-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server plugin -date: 2024-01-04 +date: 2024-01-05 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 31ac9457e072f..f73490a95c855 100644 --- a/api_docs/kbn_core_i18n_server_internal.mdx +++ b/api_docs/kbn_core_i18n_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-internal title: "@kbn/core-i18n-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 47ccee6e6cd15..ef90dab3f1ad8 100644 --- a/api_docs/kbn_core_i18n_server_mocks.mdx +++ b/api_docs/kbn_core_i18n_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-mocks title: "@kbn/core-i18n-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 2ed3ed3355a46..1b36c7da81338 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser-mocks title: "@kbn/core-injected-metadata-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 24be40a1fc587..8597ee8c0c58a 100644 --- a/api_docs/kbn_core_integrations_browser_internal.mdx +++ b/api_docs/kbn_core_integrations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-internal title: "@kbn/core-integrations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 e1e5c04231041..6d73ad37a3a4e 100644 --- a/api_docs/kbn_core_integrations_browser_mocks.mdx +++ b/api_docs/kbn_core_integrations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-mocks title: "@kbn/core-integrations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-mocks'] --- import kbnCoreIntegrationsBrowserMocksObj from './kbn_core_integrations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser.mdx b/api_docs/kbn_core_lifecycle_browser.mdx index 64ffdd809b2a6..e15a9cda86c0a 100644 --- a/api_docs/kbn_core_lifecycle_browser.mdx +++ b/api_docs/kbn_core_lifecycle_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser title: "@kbn/core-lifecycle-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 6e94acb61527b..f1a80b337c646 100644 --- a/api_docs/kbn_core_lifecycle_browser_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser-mocks title: "@kbn/core-lifecycle-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 fc5a818242d33..fb234bfd464e9 100644 --- a/api_docs/kbn_core_lifecycle_server.mdx +++ b/api_docs/kbn_core_lifecycle_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server title: "@kbn/core-lifecycle-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server plugin -date: 2024-01-04 +date: 2024-01-05 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 d66a001fbed30..c050429f94976 100644 --- a/api_docs/kbn_core_lifecycle_server_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server-mocks title: "@kbn/core-lifecycle-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 584b2355c3273..4a382b53f4034 100644 --- a/api_docs/kbn_core_logging_browser_mocks.mdx +++ b/api_docs/kbn_core_logging_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-browser-mocks title: "@kbn/core-logging-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 a1e0764981126..a1be0d78c787e 100644 --- a/api_docs/kbn_core_logging_common_internal.mdx +++ b/api_docs/kbn_core_logging_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-common-internal title: "@kbn/core-logging-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-common-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 431cd7f5a46b7..d10d6f1cb0fbf 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server plugin -date: 2024-01-04 +date: 2024-01-05 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 89e76e1e5d977..1cb9d7a42a66b 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 7706403fd0843..76e0e48e87d16 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 13f01e4c371d4..68bcc653afe36 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-internal title: "@kbn/core-metrics-collectors-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 1f612d9b47e42..9be45a959922a 100644 --- a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-mocks title: "@kbn/core-metrics-collectors-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 a5110c2ef5806..f91bee45de346 100644 --- a/api_docs/kbn_core_metrics_server.mdx +++ b/api_docs/kbn_core_metrics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server title: "@kbn/core-metrics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server plugin -date: 2024-01-04 +date: 2024-01-05 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 0794553156ba8..08fd3abf4b2f2 100644 --- a/api_docs/kbn_core_metrics_server_internal.mdx +++ b/api_docs/kbn_core_metrics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-internal title: "@kbn/core-metrics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 1fcb936b77402..0a1cf0c52011e 100644 --- a/api_docs/kbn_core_metrics_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-mocks title: "@kbn/core-metrics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 e9d8e7bd63339..cdf78183d3627 100644 --- a/api_docs/kbn_core_mount_utils_browser.mdx +++ b/api_docs/kbn_core_mount_utils_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser title: "@kbn/core-mount-utils-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 41847b2965ce1..b933d9fb7b074 100644 --- a/api_docs/kbn_core_node_server.mdx +++ b/api_docs/kbn_core_node_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server title: "@kbn/core-node-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server plugin -date: 2024-01-04 +date: 2024-01-05 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 dc5608723d689..09603fc421f92 100644 --- a/api_docs/kbn_core_node_server_internal.mdx +++ b/api_docs/kbn_core_node_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-internal title: "@kbn/core-node-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 74e310e07bc4d..d6b92cf6550ff 100644 --- a/api_docs/kbn_core_node_server_mocks.mdx +++ b/api_docs/kbn_core_node_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-mocks title: "@kbn/core-node-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 3c89672e3fcb5..9b1954f72aea3 100644 --- a/api_docs/kbn_core_notifications_browser.mdx +++ b/api_docs/kbn_core_notifications_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser title: "@kbn/core-notifications-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 f68349b2df2bd..8c0198cc375f2 100644 --- a/api_docs/kbn_core_notifications_browser_internal.mdx +++ b/api_docs/kbn_core_notifications_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-internal title: "@kbn/core-notifications-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 aa66bff4ae8c5..8321d240778a3 100644 --- a/api_docs/kbn_core_notifications_browser_mocks.mdx +++ b/api_docs/kbn_core_notifications_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-mocks title: "@kbn/core-notifications-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 099c145770adc..dcd73424735c7 100644 --- a/api_docs/kbn_core_overlays_browser.mdx +++ b/api_docs/kbn_core_overlays_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser title: "@kbn/core-overlays-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 5ee90e5a9a9fd..f8d6214e106b7 100644 --- a/api_docs/kbn_core_overlays_browser_internal.mdx +++ b/api_docs/kbn_core_overlays_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-internal title: "@kbn/core-overlays-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 aca97bed11b21..3dd3b0dfe1827 100644 --- a/api_docs/kbn_core_overlays_browser_mocks.mdx +++ b/api_docs/kbn_core_overlays_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-mocks title: "@kbn/core-overlays-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 3ad8d49e085d4..99b2909488b72 100644 --- a/api_docs/kbn_core_plugins_browser.mdx +++ b/api_docs/kbn_core_plugins_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser title: "@kbn/core-plugins-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 7517e87c6bf45..05bb9690c66da 100644 --- a/api_docs/kbn_core_plugins_browser_mocks.mdx +++ b/api_docs/kbn_core_plugins_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser-mocks title: "@kbn/core-plugins-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser-mocks'] --- import kbnCorePluginsBrowserMocksObj from './kbn_core_plugins_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_browser.mdx b/api_docs/kbn_core_plugins_contracts_browser.mdx index 2d32821e57a68..745e3ff7dc368 100644 --- a/api_docs/kbn_core_plugins_contracts_browser.mdx +++ b/api_docs/kbn_core_plugins_contracts_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-browser title: "@kbn/core-plugins-contracts-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-browser plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-browser'] --- import kbnCorePluginsContractsBrowserObj from './kbn_core_plugins_contracts_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_server.mdx b/api_docs/kbn_core_plugins_contracts_server.mdx index 3a622d5b19917..dd9290362f01e 100644 --- a/api_docs/kbn_core_plugins_contracts_server.mdx +++ b/api_docs/kbn_core_plugins_contracts_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-server title: "@kbn/core-plugins-contracts-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-server plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-server'] --- import kbnCorePluginsContractsServerObj from './kbn_core_plugins_contracts_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server.mdx b/api_docs/kbn_core_plugins_server.mdx index e97622f466a7f..22e9bdc289907 100644 --- a/api_docs/kbn_core_plugins_server.mdx +++ b/api_docs/kbn_core_plugins_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server title: "@kbn/core-plugins-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server plugin -date: 2024-01-04 +date: 2024-01-05 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 789728222a03c..141a858f1514f 100644 --- a/api_docs/kbn_core_plugins_server_mocks.mdx +++ b/api_docs/kbn_core_plugins_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server-mocks title: "@kbn/core-plugins-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 3188532eef0c4..78745c8f8794d 100644 --- a/api_docs/kbn_core_preboot_server.mdx +++ b/api_docs/kbn_core_preboot_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server title: "@kbn/core-preboot-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server plugin -date: 2024-01-04 +date: 2024-01-05 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 9abf502bc9841..ac0c2b312d4f0 100644 --- a/api_docs/kbn_core_preboot_server_mocks.mdx +++ b/api_docs/kbn_core_preboot_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server-mocks title: "@kbn/core-preboot-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 1b65c430646de..2eaff65af4b9e 100644 --- a/api_docs/kbn_core_rendering_browser_mocks.mdx +++ b/api_docs/kbn_core_rendering_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-browser-mocks title: "@kbn/core-rendering-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 269a838711fe1..cac034b79dbb5 100644 --- a/api_docs/kbn_core_rendering_server_internal.mdx +++ b/api_docs/kbn_core_rendering_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-internal title: "@kbn/core-rendering-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 530d51da435ae..ab6260c4eb1db 100644 --- a/api_docs/kbn_core_rendering_server_mocks.mdx +++ b/api_docs/kbn_core_rendering_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-mocks title: "@kbn/core-rendering-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 d88b4b65ba87f..6ee52e34d7a5f 100644 --- a/api_docs/kbn_core_root_server_internal.mdx +++ b/api_docs/kbn_core_root_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-root-server-internal title: "@kbn/core-root-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-root-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-root-server-internal'] --- import kbnCoreRootServerInternalObj from './kbn_core_root_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index 405eb70d599cb..a4696878794f9 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.mdx +++ b/api_docs/kbn_core_saved_objects_api_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-browser title: "@kbn/core-saved-objects-api-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 36f8838849be8..a2a20ce874dfe 100644 --- a/api_docs/kbn_core_saved_objects_api_server.mdx +++ b/api_docs/kbn_core_saved_objects_api_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server title: "@kbn/core-saved-objects-api-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx index 690c0b69d4244..315bd86bcfe8f 100644 --- a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-mocks title: "@kbn/core-saved-objects-api-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 0dbdf60396e53..c6fad755d60d3 100644 --- a/api_docs/kbn_core_saved_objects_base_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-internal title: "@kbn/core-saved-objects-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 ea3ea08c9248e..d352c77e86b6f 100644 --- a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-mocks title: "@kbn/core-saved-objects-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 8ea6c02a57b23..2386bbb345836 100644 --- a/api_docs/kbn_core_saved_objects_browser.mdx +++ b/api_docs/kbn_core_saved_objects_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser title: "@kbn/core-saved-objects-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 0819d5a1e7997..f38f8a175534d 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.mdx +++ b/api_docs/kbn_core_saved_objects_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-internal title: "@kbn/core-saved-objects-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 4658f309b11a5..e2123b9db7fe9 100644 --- a/api_docs/kbn_core_saved_objects_browser_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-mocks title: "@kbn/core-saved-objects-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-mocks'] --- import kbnCoreSavedObjectsBrowserMocksObj from './kbn_core_saved_objects_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index a74bec6b40adf..a03a55579e7c8 100644 --- a/api_docs/kbn_core_saved_objects_common.mdx +++ b/api_docs/kbn_core_saved_objects_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-common title: "@kbn/core-saved-objects-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-common plugin -date: 2024-01-04 +date: 2024-01-05 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 1a4c01991982f..d447d007c9efe 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-internal title: "@kbn/core-saved-objects-import-export-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 f37847eb15bda..e9c44ca486b15 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-mocks title: "@kbn/core-saved-objects-import-export-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 be10a7df2c69e..6557ea3b88b01 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-internal title: "@kbn/core-saved-objects-migration-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 83d236a7c90b8..ca68c544a4a84 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-mocks title: "@kbn/core-saved-objects-migration-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 073d01306e15f..528d68226c1e8 100644 --- a/api_docs/kbn_core_saved_objects_server.mdx +++ b/api_docs/kbn_core_saved_objects_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server title: "@kbn/core-saved-objects-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server plugin -date: 2024-01-04 +date: 2024-01-05 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 ff992ba279e5f..53029290bbcef 100644 --- a/api_docs/kbn_core_saved_objects_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-internal title: "@kbn/core-saved-objects-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 d0c9b94683c4c..aebb6f5ffb2a1 100644 --- a/api_docs/kbn_core_saved_objects_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-mocks title: "@kbn/core-saved-objects-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 9a655a53f3d2c..8de3b757d7fe7 100644 --- a/api_docs/kbn_core_saved_objects_utils_server.mdx +++ b/api_docs/kbn_core_saved_objects_utils_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-utils-server title: "@kbn/core-saved-objects-utils-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-utils-server plugin -date: 2024-01-04 +date: 2024-01-05 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 30d1a76ba87a6..6790c9b264fd0 100644 --- a/api_docs/kbn_core_status_common.mdx +++ b/api_docs/kbn_core_status_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common title: "@kbn/core-status-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common plugin -date: 2024-01-04 +date: 2024-01-05 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 e7b9d22253332..da0ed41bb9411 100644 --- a/api_docs/kbn_core_status_common_internal.mdx +++ b/api_docs/kbn_core_status_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common-internal title: "@kbn/core-status-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 1ced970793db3..2640368c30be9 100644 --- a/api_docs/kbn_core_status_server.mdx +++ b/api_docs/kbn_core_status_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server title: "@kbn/core-status-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server plugin -date: 2024-01-04 +date: 2024-01-05 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 cb2db0211eeb1..772cd4def6a63 100644 --- a/api_docs/kbn_core_status_server_internal.mdx +++ b/api_docs/kbn_core_status_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-internal title: "@kbn/core-status-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 2defa9b66cd1e..8e08cf85ec1ac 100644 --- a/api_docs/kbn_core_status_server_mocks.mdx +++ b/api_docs/kbn_core_status_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-mocks title: "@kbn/core-status-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 bcd02b5b63d8f..272f643a6321b 100644 --- a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx +++ b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-deprecations-getters title: "@kbn/core-test-helpers-deprecations-getters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-deprecations-getters plugin -date: 2024-01-04 +date: 2024-01-05 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 7c28f8c40e05c..534bbae8b4697 100644 --- a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx +++ b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-http-setup-browser title: "@kbn/core-test-helpers-http-setup-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-http-setup-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 d1f7537721766..acdfb8291f5ce 100644 --- a/api_docs/kbn_core_test_helpers_kbn_server.mdx +++ b/api_docs/kbn_core_test_helpers_kbn_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-kbn-server title: "@kbn/core-test-helpers-kbn-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-kbn-server plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-kbn-server'] --- import kbnCoreTestHelpersKbnServerObj from './kbn_core_test_helpers_kbn_server.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_model_versions.mdx b/api_docs/kbn_core_test_helpers_model_versions.mdx index df6c2317422f8..8f8d5cd2f0301 100644 --- a/api_docs/kbn_core_test_helpers_model_versions.mdx +++ b/api_docs/kbn_core_test_helpers_model_versions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-model-versions title: "@kbn/core-test-helpers-model-versions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-model-versions plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-model-versions'] --- import kbnCoreTestHelpersModelVersionsObj from './kbn_core_test_helpers_model_versions.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx index a5d5ec6bcf424..bece1dfffd54b 100644 --- a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx +++ b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-so-type-serializer title: "@kbn/core-test-helpers-so-type-serializer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-so-type-serializer plugin -date: 2024-01-04 +date: 2024-01-05 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 3812d80d05841..03096fa4ea6b8 100644 --- a/api_docs/kbn_core_test_helpers_test_utils.mdx +++ b/api_docs/kbn_core_test_helpers_test_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-test-utils title: "@kbn/core-test-helpers-test-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-test-utils plugin -date: 2024-01-04 +date: 2024-01-05 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 ad3d2637f65c3..10c78c84e5977 100644 --- a/api_docs/kbn_core_theme_browser.mdx +++ b/api_docs/kbn_core_theme_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser title: "@kbn/core-theme-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] --- import kbnCoreThemeBrowserObj from './kbn_core_theme_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index 1c655b9d37744..8096b2c0c6b2c 100644 --- a/api_docs/kbn_core_theme_browser_mocks.mdx +++ b/api_docs/kbn_core_theme_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-mocks title: "@kbn/core-theme-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 933b7613d430e..0806dcc0e27e4 100644 --- a/api_docs/kbn_core_ui_settings_browser.mdx +++ b/api_docs/kbn_core_ui_settings_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser title: "@kbn/core-ui-settings-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 1759294c3ede1..591c1f9eda155 100644 --- a/api_docs/kbn_core_ui_settings_browser_internal.mdx +++ b/api_docs/kbn_core_ui_settings_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-internal title: "@kbn/core-ui-settings-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 711277a14d313..c5ed348ea2843 100644 --- a/api_docs/kbn_core_ui_settings_browser_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-mocks title: "@kbn/core-ui-settings-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 48f92b475d5ea..c2713fdc462d8 100644 --- a/api_docs/kbn_core_ui_settings_common.mdx +++ b/api_docs/kbn_core_ui_settings_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-common title: "@kbn/core-ui-settings-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-common plugin -date: 2024-01-04 +date: 2024-01-05 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 9ab86721089f6..fd65be4fcb46e 100644 --- a/api_docs/kbn_core_ui_settings_server.mdx +++ b/api_docs/kbn_core_ui_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server title: "@kbn/core-ui-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server plugin -date: 2024-01-04 +date: 2024-01-05 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 a177e83347b19..cab535e4d818c 100644 --- a/api_docs/kbn_core_ui_settings_server_internal.mdx +++ b/api_docs/kbn_core_ui_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-internal title: "@kbn/core-ui-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 d82f2f595f8eb..8cd3baf2d70bd 100644 --- a/api_docs/kbn_core_ui_settings_server_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-mocks title: "@kbn/core-ui-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 c1fce322f9508..b2976124fb3ed 100644 --- a/api_docs/kbn_core_usage_data_server.mdx +++ b/api_docs/kbn_core_usage_data_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server title: "@kbn/core-usage-data-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server plugin -date: 2024-01-04 +date: 2024-01-05 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 420a7ba708a2f..46fe662e811a9 100644 --- a/api_docs/kbn_core_usage_data_server_internal.mdx +++ b/api_docs/kbn_core_usage_data_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-internal title: "@kbn/core-usage-data-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 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 8df47910b2611..f333f187c4c1c 100644 --- a/api_docs/kbn_core_usage_data_server_mocks.mdx +++ b/api_docs/kbn_core_usage_data_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-mocks title: "@kbn/core-usage-data-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-mocks'] --- import kbnCoreUsageDataServerMocksObj from './kbn_core_usage_data_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server.mdx b/api_docs/kbn_core_user_settings_server.mdx index b4252ff9424a0..f95c6ea99795f 100644 --- a/api_docs/kbn_core_user_settings_server.mdx +++ b/api_docs/kbn_core_user_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server title: "@kbn/core-user-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server'] --- import kbnCoreUserSettingsServerObj from './kbn_core_user_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server_internal.mdx b/api_docs/kbn_core_user_settings_server_internal.mdx index 3fcfb92e24af9..0a5de0b387e34 100644 --- a/api_docs/kbn_core_user_settings_server_internal.mdx +++ b/api_docs/kbn_core_user_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server-internal title: "@kbn/core-user-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server-internal plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server-internal'] --- import kbnCoreUserSettingsServerInternalObj from './kbn_core_user_settings_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server_mocks.mdx b/api_docs/kbn_core_user_settings_server_mocks.mdx index bcd3b45938020..a469906822a7f 100644 --- a/api_docs/kbn_core_user_settings_server_mocks.mdx +++ b/api_docs/kbn_core_user_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server-mocks title: "@kbn/core-user-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server-mocks plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server-mocks'] --- import kbnCoreUserSettingsServerMocksObj from './kbn_core_user_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_crypto.mdx b/api_docs/kbn_crypto.mdx index 1756c3f446e3e..62d9f95e09516 100644 --- a/api_docs/kbn_crypto.mdx +++ b/api_docs/kbn_crypto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto title: "@kbn/crypto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto plugin -date: 2024-01-04 +date: 2024-01-05 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 df724db842c5a..d7ca756cce0e6 100644 --- a/api_docs/kbn_crypto_browser.mdx +++ b/api_docs/kbn_crypto_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto-browser title: "@kbn/crypto-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto-browser plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_custom_icons.mdx b/api_docs/kbn_custom_icons.mdx index f2a931c88273c..a0ca9002c0700 100644 --- a/api_docs/kbn_custom_icons.mdx +++ b/api_docs/kbn_custom_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-icons title: "@kbn/custom-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-icons plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-icons'] --- import kbnCustomIconsObj from './kbn_custom_icons.devdocs.json'; diff --git a/api_docs/kbn_custom_integrations.mdx b/api_docs/kbn_custom_integrations.mdx index 99d54015c69a1..3fcd8906bd390 100644 --- a/api_docs/kbn_custom_integrations.mdx +++ b/api_docs/kbn_custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-integrations title: "@kbn/custom-integrations" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-integrations plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-integrations'] --- import kbnCustomIntegrationsObj from './kbn_custom_integrations.devdocs.json'; diff --git a/api_docs/kbn_cypress_config.mdx b/api_docs/kbn_cypress_config.mdx index e9a58ed538b8f..bef6cd7cc7ac4 100644 --- a/api_docs/kbn_cypress_config.mdx +++ b/api_docs/kbn_cypress_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cypress-config title: "@kbn/cypress-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cypress-config plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cypress-config'] --- import kbnCypressConfigObj from './kbn_cypress_config.devdocs.json'; diff --git a/api_docs/kbn_data_service.mdx b/api_docs/kbn_data_service.mdx index 643081b1d4dae..6f263e3da035f 100644 --- a/api_docs/kbn_data_service.mdx +++ b/api_docs/kbn_data_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-service title: "@kbn/data-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-service plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-service'] --- import kbnDataServiceObj from './kbn_data_service.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index 81c40771e0bb7..16beebc820846 100644 --- a/api_docs/kbn_datemath.mdx +++ b/api_docs/kbn_datemath.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-datemath title: "@kbn/datemath" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/datemath plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_analytics.mdx b/api_docs/kbn_deeplinks_analytics.mdx index 2f5c0b0c898e2..6c571e0fe0b4e 100644 --- a/api_docs/kbn_deeplinks_analytics.mdx +++ b/api_docs/kbn_deeplinks_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-analytics title: "@kbn/deeplinks-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-analytics plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-analytics'] --- import kbnDeeplinksAnalyticsObj from './kbn_deeplinks_analytics.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_devtools.mdx b/api_docs/kbn_deeplinks_devtools.mdx index be2b50795b6b8..2da79e7a1f597 100644 --- a/api_docs/kbn_deeplinks_devtools.mdx +++ b/api_docs/kbn_deeplinks_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-devtools title: "@kbn/deeplinks-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-devtools plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-devtools'] --- import kbnDeeplinksDevtoolsObj from './kbn_deeplinks_devtools.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_management.mdx b/api_docs/kbn_deeplinks_management.mdx index 9a9c64b5db9b0..95bff06def67f 100644 --- a/api_docs/kbn_deeplinks_management.mdx +++ b/api_docs/kbn_deeplinks_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-management title: "@kbn/deeplinks-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-management plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-management'] --- import kbnDeeplinksManagementObj from './kbn_deeplinks_management.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_ml.mdx b/api_docs/kbn_deeplinks_ml.mdx index 7afa5a8820ef3..5a9306c0523aa 100644 --- a/api_docs/kbn_deeplinks_ml.mdx +++ b/api_docs/kbn_deeplinks_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-ml title: "@kbn/deeplinks-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-ml plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-ml'] --- import kbnDeeplinksMlObj from './kbn_deeplinks_ml.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_observability.mdx b/api_docs/kbn_deeplinks_observability.mdx index f43d2395f1399..da7f8ac91cd99 100644 --- a/api_docs/kbn_deeplinks_observability.mdx +++ b/api_docs/kbn_deeplinks_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-observability title: "@kbn/deeplinks-observability" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-observability plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-observability'] --- import kbnDeeplinksObservabilityObj from './kbn_deeplinks_observability.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_search.mdx b/api_docs/kbn_deeplinks_search.mdx index f213317ca7a0a..8957459c87878 100644 --- a/api_docs/kbn_deeplinks_search.mdx +++ b/api_docs/kbn_deeplinks_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-search title: "@kbn/deeplinks-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-search plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-search'] --- import kbnDeeplinksSearchObj from './kbn_deeplinks_search.devdocs.json'; diff --git a/api_docs/kbn_default_nav_analytics.mdx b/api_docs/kbn_default_nav_analytics.mdx index 2cac4b3d4fce7..0584a1becfdd9 100644 --- a/api_docs/kbn_default_nav_analytics.mdx +++ b/api_docs/kbn_default_nav_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-analytics title: "@kbn/default-nav-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-analytics plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-analytics'] --- import kbnDefaultNavAnalyticsObj from './kbn_default_nav_analytics.devdocs.json'; diff --git a/api_docs/kbn_default_nav_devtools.mdx b/api_docs/kbn_default_nav_devtools.mdx index 6fcd2c17b24e4..d1172c422ae54 100644 --- a/api_docs/kbn_default_nav_devtools.mdx +++ b/api_docs/kbn_default_nav_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-devtools title: "@kbn/default-nav-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-devtools plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-devtools'] --- import kbnDefaultNavDevtoolsObj from './kbn_default_nav_devtools.devdocs.json'; diff --git a/api_docs/kbn_default_nav_management.mdx b/api_docs/kbn_default_nav_management.mdx index d6165f2f72d22..97f2b0e545f33 100644 --- a/api_docs/kbn_default_nav_management.mdx +++ b/api_docs/kbn_default_nav_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-management title: "@kbn/default-nav-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-management plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-management'] --- import kbnDefaultNavManagementObj from './kbn_default_nav_management.devdocs.json'; diff --git a/api_docs/kbn_default_nav_ml.mdx b/api_docs/kbn_default_nav_ml.mdx index b5a858abc5056..ea8203e7807d9 100644 --- a/api_docs/kbn_default_nav_ml.mdx +++ b/api_docs/kbn_default_nav_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-ml title: "@kbn/default-nav-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-ml plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-ml'] --- import kbnDefaultNavMlObj from './kbn_default_nav_ml.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index ff8d6d8c74371..0bcb226be09e3 100644 --- a/api_docs/kbn_dev_cli_errors.mdx +++ b/api_docs/kbn_dev_cli_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-errors title: "@kbn/dev-cli-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-errors plugin -date: 2024-01-04 +date: 2024-01-05 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 41dc8147ad3a4..4a5e0f11ef6c5 100644 --- a/api_docs/kbn_dev_cli_runner.mdx +++ b/api_docs/kbn_dev_cli_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-runner title: "@kbn/dev-cli-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-runner plugin -date: 2024-01-04 +date: 2024-01-05 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 e4581551a701a..652c7f260d807 100644 --- a/api_docs/kbn_dev_proc_runner.mdx +++ b/api_docs/kbn_dev_proc_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-proc-runner title: "@kbn/dev-proc-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-proc-runner plugin -date: 2024-01-04 +date: 2024-01-05 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 d8eba73051f31..c4901a654547c 100644 --- a/api_docs/kbn_dev_utils.mdx +++ b/api_docs/kbn_dev_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-utils title: "@kbn/dev-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_discover_utils.mdx b/api_docs/kbn_discover_utils.mdx index 834b54a7cc8b5..0aebf568df0e5 100644 --- a/api_docs/kbn_discover_utils.mdx +++ b/api_docs/kbn_discover_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-discover-utils title: "@kbn/discover-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/discover-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-utils'] --- import kbnDiscoverUtilsObj from './kbn_discover_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index 26ad9f0b338ad..5a5b37d1782b4 100644 --- a/api_docs/kbn_doc_links.mdx +++ b/api_docs/kbn_doc_links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-doc-links title: "@kbn/doc-links" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/doc-links plugin -date: 2024-01-04 +date: 2024-01-05 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 97ec6e097df36..32348f44bd009 100644 --- a/api_docs/kbn_docs_utils.mdx +++ b/api_docs/kbn_docs_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-docs-utils title: "@kbn/docs-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/docs-utils plugin -date: 2024-01-04 +date: 2024-01-05 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 69962080ec4df..9828cab37f002 100644 --- a/api_docs/kbn_dom_drag_drop.mdx +++ b/api_docs/kbn_dom_drag_drop.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dom-drag-drop title: "@kbn/dom-drag-drop" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dom-drag-drop plugin -date: 2024-01-04 +date: 2024-01-05 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 b9a95c21a65f4..8508582482b8b 100644 --- a/api_docs/kbn_ebt_tools.mdx +++ b/api_docs/kbn_ebt_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ebt-tools title: "@kbn/ebt-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ebt-tools plugin -date: 2024-01-04 +date: 2024-01-05 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 655a8f4727802..4286c1ccfe661 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: 2024-01-04 +date: 2024-01-05 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 5f82c57739561..f96a9ec52b922 100644 --- a/api_docs/kbn_ecs_data_quality_dashboard.mdx +++ b/api_docs/kbn_ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs-data-quality-dashboard title: "@kbn/ecs-data-quality-dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs-data-quality-dashboard plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs-data-quality-dashboard'] --- import kbnEcsDataQualityDashboardObj from './kbn_ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/kbn_elastic_agent_utils.mdx b/api_docs/kbn_elastic_agent_utils.mdx index c37ce828a8515..f6df41c4f6dfc 100644 --- a/api_docs/kbn_elastic_agent_utils.mdx +++ b/api_docs/kbn_elastic_agent_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-agent-utils title: "@kbn/elastic-agent-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-agent-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-agent-utils'] --- import kbnElasticAgentUtilsObj from './kbn_elastic_agent_utils.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant.mdx b/api_docs/kbn_elastic_assistant.mdx index 1d76023b58651..909678cae3168 100644 --- a/api_docs/kbn_elastic_assistant.mdx +++ b/api_docs/kbn_elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant title: "@kbn/elastic-assistant" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant'] --- import kbnElasticAssistantObj from './kbn_elastic_assistant.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant_common.mdx b/api_docs/kbn_elastic_assistant_common.mdx index dc32cd0edca70..e2e4f236a1a03 100644 --- a/api_docs/kbn_elastic_assistant_common.mdx +++ b/api_docs/kbn_elastic_assistant_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant-common title: "@kbn/elastic-assistant-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant-common plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant-common'] --- import kbnElasticAssistantCommonObj from './kbn_elastic_assistant_common.devdocs.json'; diff --git a/api_docs/kbn_es.mdx b/api_docs/kbn_es.mdx index fef9a0cc1a18e..da45af0b343e9 100644 --- a/api_docs/kbn_es.mdx +++ b/api_docs/kbn_es.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es title: "@kbn/es" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es plugin -date: 2024-01-04 +date: 2024-01-05 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 cb8a2c1ea7cb0..67abe05e9bf28 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-archiver plugin -date: 2024-01-04 +date: 2024-01-05 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 211c745a6f22a..2c423d62f92f5 100644 --- a/api_docs/kbn_es_errors.mdx +++ b/api_docs/kbn_es_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-errors title: "@kbn/es-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-errors plugin -date: 2024-01-04 +date: 2024-01-05 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 74a7c73aec306..6bdb08de3efe7 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-query title: "@kbn/es-query" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-query plugin -date: 2024-01-04 +date: 2024-01-05 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 2239b14ba2ac0..0b2165aa8af4e 100644 --- a/api_docs/kbn_es_types.mdx +++ b/api_docs/kbn_es_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-types title: "@kbn/es-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-types plugin -date: 2024-01-04 +date: 2024-01-05 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 a87f273b8bdd2..4791ea44d6b3a 100644 --- a/api_docs/kbn_eslint_plugin_imports.mdx +++ b/api_docs/kbn_eslint_plugin_imports.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-eslint-plugin-imports title: "@kbn/eslint-plugin-imports" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/eslint-plugin-imports plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_common.mdx b/api_docs/kbn_event_annotation_common.mdx index a78fb63d369e0..e5fcb23a65682 100644 --- a/api_docs/kbn_event_annotation_common.mdx +++ b/api_docs/kbn_event_annotation_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-common title: "@kbn/event-annotation-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-common plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-common'] --- import kbnEventAnnotationCommonObj from './kbn_event_annotation_common.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_components.mdx b/api_docs/kbn_event_annotation_components.mdx index 7b0106699b554..5187ac07cd6f6 100644 --- a/api_docs/kbn_event_annotation_components.mdx +++ b/api_docs/kbn_event_annotation_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-components title: "@kbn/event-annotation-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-components plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-components'] --- import kbnEventAnnotationComponentsObj from './kbn_event_annotation_components.devdocs.json'; diff --git a/api_docs/kbn_expandable_flyout.mdx b/api_docs/kbn_expandable_flyout.mdx index ae08844018103..8807a3ef06695 100644 --- a/api_docs/kbn_expandable_flyout.mdx +++ b/api_docs/kbn_expandable_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-expandable-flyout title: "@kbn/expandable-flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/expandable-flyout plugin -date: 2024-01-04 +date: 2024-01-05 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 cb55a29f3f27a..d30d8c4c09282 100644 --- a/api_docs/kbn_field_types.mdx +++ b/api_docs/kbn_field_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-types title: "@kbn/field-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-types plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_field_utils.mdx b/api_docs/kbn_field_utils.mdx index 06b57eb8264ed..c1a49910d999a 100644 --- a/api_docs/kbn_field_utils.mdx +++ b/api_docs/kbn_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-utils title: "@kbn/field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-utils'] --- import kbnFieldUtilsObj from './kbn_field_utils.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index 0c91dccea3f64..ef45987a7a582 100644 --- a/api_docs/kbn_find_used_node_modules.mdx +++ b/api_docs/kbn_find_used_node_modules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-find-used-node-modules title: "@kbn/find-used-node-modules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/find-used-node-modules plugin -date: 2024-01-04 +date: 2024-01-05 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 1f31375de175b..222bd8a02a9f5 100644 --- a/api_docs/kbn_ftr_common_functional_services.mdx +++ b/api_docs/kbn_ftr_common_functional_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-services title: "@kbn/ftr-common-functional-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-services plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-services'] --- import kbnFtrCommonFunctionalServicesObj from './kbn_ftr_common_functional_services.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_ui_services.devdocs.json b/api_docs/kbn_ftr_common_functional_ui_services.devdocs.json index 79a57d84974d8..e2f2105db52c4 100644 --- a/api_docs/kbn_ftr_common_functional_ui_services.devdocs.json +++ b/api_docs/kbn_ftr_common_functional_ui_services.devdocs.json @@ -17,10 +17,9981 @@ "objects": [] }, "common": { - "classes": [], + "classes": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper", + "type": "Class", + "tags": [], + "label": "WebElementWrapper", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.isChromium", + "type": "boolean", + "tags": [], + "label": "isChromium", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.create", + "type": "Function", + "tags": [], + "label": "create", + "description": [], + "signature": [ + "(webElement: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.WebElementWrapper", + "text": "WebElementWrapper" + }, + " | ", + "WebElement", + ", locator: ", + "By", + " | null, driver: ", + "WebDriver", + ", timeout: number, fixedHeaderHeight: number, logger: ", + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.ToolingLog", + "text": "ToolingLog" + }, + ", browserType: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.Browsers", + "text": "Browsers" + }, + ") => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.WebElementWrapper", + "text": "WebElementWrapper" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.create.$1", + "type": "CompoundType", + "tags": [], + "label": "webElement", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.WebElementWrapper", + "text": "WebElementWrapper" + }, + " | ", + "WebElement" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.create.$2", + "type": "CompoundType", + "tags": [], + "label": "locator", + "description": [], + "signature": [ + "By", + " | null" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.create.$3", + "type": "Object", + "tags": [], + "label": "driver", + "description": [], + "signature": [ + "WebDriver" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.create.$4", + "type": "number", + "tags": [], + "label": "timeout", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.create.$5", + "type": "number", + "tags": [], + "label": "fixedHeaderHeight", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.create.$6", + "type": "Object", + "tags": [], + "label": "logger", + "description": [], + "signature": [ + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.ToolingLog", + "text": "ToolingLog" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.create.$7", + "type": "Enum", + "tags": [], + "label": "browserType", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.Browsers", + "text": "Browsers" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "_webElement", + "description": [], + "signature": [ + "WebElement" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.Unnamed.$2", + "type": "CompoundType", + "tags": [], + "label": "locator", + "description": [], + "signature": [ + "By", + " | null" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.Unnamed.$3", + "type": "Object", + "tags": [], + "label": "driver", + "description": [], + "signature": [ + "WebDriver" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.Unnamed.$4", + "type": "number", + "tags": [], + "label": "timeout", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.Unnamed.$5", + "type": "number", + "tags": [], + "label": "fixedHeaderHeight", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.Unnamed.$6", + "type": "Object", + "tags": [], + "label": "logger", + "description": [], + "signature": [ + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.ToolingLog", + "text": "ToolingLog" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.Unnamed.$7", + "type": "Enum", + "tags": [], + "label": "browserType", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.Browsers", + "text": "Browsers" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.isDisplayed", + "type": "Function", + "tags": [ + "return" + ], + "label": "isDisplayed", + "description": [ + "\nReturns whether or not the element would be visible to an actual user. This means\nthat the following types of elements are considered to be not displayed:\n\n - Elements with display: none\n - Elements with visibility: hidden\n - Elements positioned outside of the viewport that cannot be scrolled into view\n - Elements with opacity: 0\n - Elements with no offsetWidth or offsetHeight\n\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#isDisplayed\n" + ], + "signature": [ + "() => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.isEnabled", + "type": "Function", + "tags": [ + "return" + ], + "label": "isEnabled", + "description": [ + "\nTests whether this element is enabled, as dictated by the disabled attribute.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#isEnabled\n" + ], + "signature": [ + "() => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.isSelected", + "type": "Function", + "tags": [ + "return" + ], + "label": "isSelected", + "description": [ + "\nTests whether this element is selected.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#isSelected\n" + ], + "signature": [ + "() => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.click", + "type": "Function", + "tags": [ + "return" + ], + "label": "click", + "description": [ + "\nClicks on this element.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#click\n" + ], + "signature": [ + "(topOffset?: number | undefined) => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.click.$1", + "type": "number", + "tags": [], + "label": "topOffset", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.focus", + "type": "Function", + "tags": [ + "return" + ], + "label": "focus", + "description": [ + "\nFocuses this element.\n" + ], + "signature": [ + "() => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.openHref", + "type": "Function", + "tags": [ + "return" + ], + "label": "openHref", + "description": [ + "\nIf possible, opens 'href' of this element directly through the URL\n" + ], + "signature": [ + "() => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.elementHasClass", + "type": "Function", + "tags": [ + "return" + ], + "label": "elementHasClass", + "description": [ + "\nCheck if webelement wrapper has a specific class.\n" + ], + "signature": [ + "(className: string) => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.elementHasClass.$1", + "type": "string", + "tags": [], + "label": "className", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.clearValue", + "type": "Function", + "tags": [ + "default" + ], + "label": "clearValue", + "description": [ + "\nClear the value of this element. This command has no effect if the underlying DOM element\nis neither a text INPUT element nor a TEXTAREA element.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#clear\n" + ], + "signature": [ + "(options?: ClearOptions) => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.clearValue.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [ + "option to clear input with JS: `arguments[0].value=''`" + ], + "signature": [ + "ClearOptions" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.clearValueWithKeyboard", + "type": "Function", + "tags": [ + "default" + ], + "label": "clearValueWithKeyboard", + "description": [ + "\nClear the value of this element using Keyboard" + ], + "signature": [ + "(options?: TypeOptions) => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.clearValueWithKeyboard.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [ + "to input characters one by one" + ], + "signature": [ + "TypeOptions" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.selectValueWithKeyboard", + "type": "Function", + "tags": [], + "label": "selectValueWithKeyboard", + "description": [], + "signature": [ + "() => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.type", + "type": "Function", + "tags": [ + "return" + ], + "label": "type", + "description": [ + "\nTypes a key sequence on the DOM element represented by this instance. Modifier keys\n(SHIFT, CONTROL, ALT, META) are stateful; once a modifier is processed in the key sequence,\nthat key state is toggled until one of the following occurs:\n\nThe modifier key is encountered again in the sequence. At this point the state of the key is\ntoggled (along with the appropriate keyup/down events).\nThe input.Key.NULL key is encountered in the sequence. When this key is encountered, all\nmodifier keys current in the down state are released (with accompanying keyup events). The NULL\nkey can be used to simulate common keyboard shortcuts.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#sendKeys\n" + ], + "signature": [ + "(value: string | string[], options?: TypeOptions) => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.type.$1", + "type": "CompoundType", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "string | string[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.type.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "TypeOptions" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.pressKeys", + "type": "Function", + "tags": [], + "label": "pressKeys", + "description": [], + "signature": [ + "{ (keys: T | T[]): Promise; (keys: T | T[]): Promise; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.pressKeys.$1", + "type": "string", + "tags": [], + "label": "keys", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.getAttribute", + "type": "Function", + "tags": [], + "label": "getAttribute", + "description": [ + "\nRetrieves the current value of the given attribute of this element. Will return the current\nvalue, even if it has been modified after the page has been loaded. More exactly, this method\nwill return the value of the given attribute, unless that attribute is not present, in which\ncase the value of the property with the same name is returned. If neither value is set, null\nis returned (for example, the \"value\" property of a textarea element). The \"style\" attribute\nis converted as best can be to a text representation with a trailing semi-colon.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#getAttribute\n" + ], + "signature": [ + "(name: string) => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.getAttribute.$1", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.getComputedStyle", + "type": "Function", + "tags": [ + "return" + ], + "label": "getComputedStyle", + "description": [ + "\nRetrieves the value of a computed style property for this instance. If the element inherits\nthe named style from its parent, the parent will be queried for its value. Where possible,\ncolor values will be converted to their hex representation (e.g. #00ff00 instead of rgb(0, 255, 0)).\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#getCssValue\n" + ], + "signature": [ + "(propertyName: string) => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.getComputedStyle.$1", + "type": "string", + "tags": [], + "label": "propertyName", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.getVisibleText", + "type": "Function", + "tags": [ + "return" + ], + "label": "getVisibleText", + "description": [ + "\nGet the visible (i.e. not hidden by CSS) innerText of this element, including sub-elements,\nwithout any leading or trailing whitespace.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#getText\n" + ], + "signature": [ + "() => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.getTagName", + "type": "Function", + "tags": [], + "label": "getTagName", + "description": [], + "signature": [ + "{ (): Promise; (): Promise; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.getPosition", + "type": "Function", + "tags": [ + "return" + ], + "label": "getPosition", + "description": [ + "\nReturns an object describing an element's location, in pixels relative to the document element,\nand the element's size in pixels.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#getRect\n" + ], + "signature": [ + "() => Promise<{ height: number; width: number; x: number; y: number; }>" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.getSize", + "type": "Function", + "tags": [ + "return" + ], + "label": "getSize", + "description": [ + "\nReturns an object describing an element's location, in pixels relative to the document element,\nand the element's size in pixels.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#getRect\n" + ], + "signature": [ + "() => Promise<{ height: number; width: number; x: number; y: number; }>" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.moveMouseTo", + "type": "Function", + "tags": [ + "return" + ], + "label": "moveMouseTo", + "description": [ + "\nMoves the remote environment’s mouse cursor to the current element with optional offset\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/input_exports_Actions.html#move" + ], + "signature": [ + "(options?: { xOffset: number; yOffset: number; }) => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.moveMouseTo.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "{ xOffset: number; yOffset: number; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.clickMouseButton", + "type": "Function", + "tags": [ + "return" + ], + "label": "clickMouseButton", + "description": [ + "\nInserts an action for moving the mouse to element center, unless optional offset is provided.\nThen adds an action for left-click (down/up) with the mouse.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/input_exports_Actions.html#click\n" + ], + "signature": [ + "(options?: { xOffset: number; yOffset: number; }) => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.clickMouseButton.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "{ xOffset: number; yOffset: number; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.doubleClick", + "type": "Function", + "tags": [ + "return" + ], + "label": "doubleClick", + "description": [ + "\nInserts action for performing a double left-click with the mouse.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/input_exports_Actions.html#doubleClick" + ], + "signature": [ + "() => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findByCssSelector", + "type": "Function", + "tags": [ + "return" + ], + "label": "findByCssSelector", + "description": [ + "\nGets the first element inside this element matching the given CSS selector.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#findElement\n" + ], + "signature": [ + "(selector: string) => Promise<", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.WebElementWrapper", + "text": "WebElementWrapper" + }, + ">" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findByCssSelector.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByCssSelector", + "type": "Function", + "tags": [ + "return" + ], + "label": "findAllByCssSelector", + "description": [ + "\nGets all elements inside this element matching the given CSS selector.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#findElement\n" + ], + "signature": [ + "(selector: string, timeout?: number | undefined) => Promise<", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.WebElementWrapper", + "text": "WebElementWrapper" + }, + "[]>" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByCssSelector.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByCssSelector.$2", + "type": "number", + "tags": [], + "label": "timeout", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findByTestSubject", + "type": "Function", + "tags": [ + "return" + ], + "label": "findByTestSubject", + "description": [ + "\nGets the first element inside this element matching the given data-test-subj selector.\n" + ], + "signature": [ + "(selector: string) => Promise<", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.WebElementWrapper", + "text": "WebElementWrapper" + }, + ">" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findByTestSubject.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByTestSubject", + "type": "Function", + "tags": [ + "return" + ], + "label": "findAllByTestSubject", + "description": [ + "\nGets all elements inside this element matching the given data-test-subj selector.\n" + ], + "signature": [ + "(selector: string, timeout?: number | undefined) => Promise<", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.WebElementWrapper", + "text": "WebElementWrapper" + }, + "[]>" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByTestSubject.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByTestSubject.$2", + "type": "number", + "tags": [], + "label": "timeout", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findByClassName", + "type": "Function", + "tags": [ + "return" + ], + "label": "findByClassName", + "description": [ + "\nGets the first element inside this element matching the given CSS class name.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#findElement\n" + ], + "signature": [ + "(className: string) => Promise<", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.WebElementWrapper", + "text": "WebElementWrapper" + }, + ">" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findByClassName.$1", + "type": "string", + "tags": [], + "label": "className", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByClassName", + "type": "Function", + "tags": [ + "return" + ], + "label": "findAllByClassName", + "description": [ + "\nGets all elements inside this element matching the given CSS class name.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#findElement\n" + ], + "signature": [ + "(className: string, timeout?: number | undefined) => Promise<", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.WebElementWrapper", + "text": "WebElementWrapper" + }, + "[]>" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByClassName.$1", + "type": "string", + "tags": [], + "label": "className", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByClassName.$2", + "type": "number", + "tags": [], + "label": "timeout", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findByTagName", + "type": "Function", + "tags": [], + "label": "findByTagName", + "description": [], + "signature": [ + "{ (tagName: T): Promise<", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.WebElementWrapper", + "text": "WebElementWrapper" + }, + ">; (tagName: T): Promise<", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.WebElementWrapper", + "text": "WebElementWrapper" + }, + ">; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findByTagName.$1", + "type": "string", + "tags": [], + "label": "tagName", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByTagName", + "type": "Function", + "tags": [], + "label": "findAllByTagName", + "description": [], + "signature": [ + "{ (tagName: T, timeout?: number | undefined): Promise<", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.WebElementWrapper", + "text": "WebElementWrapper" + }, + "[]>; (tagName: T, timeout?: number | undefined): Promise<", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.WebElementWrapper", + "text": "WebElementWrapper" + }, + "[]>; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByTagName.$1", + "type": "string", + "tags": [], + "label": "tagName", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByTagName.$2", + "type": "number", + "tags": [], + "label": "timeout", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findByXpath", + "type": "Function", + "tags": [ + "return" + ], + "label": "findByXpath", + "description": [ + "\nGets the first element inside this element matching the given XPath selector.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#findElement\n" + ], + "signature": [ + "(selector: string) => Promise<", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.WebElementWrapper", + "text": "WebElementWrapper" + }, + ">" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findByXpath.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByXpath", + "type": "Function", + "tags": [ + "return" + ], + "label": "findAllByXpath", + "description": [ + "\nGets all elements inside this element matching the given XPath selector.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#findElement\n" + ], + "signature": [ + "(selector: string, timeout?: number | undefined) => Promise<", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.WebElementWrapper", + "text": "WebElementWrapper" + }, + "[]>" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByXpath.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByXpath.$2", + "type": "number", + "tags": [], + "label": "timeout", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findByPartialLinkText", + "type": "Function", + "tags": [ + "return" + ], + "label": "findByPartialLinkText", + "description": [ + "\nGets the first element inside this element matching the given partial link text.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#findElement\n" + ], + "signature": [ + "(linkText: string) => Promise<", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.WebElementWrapper", + "text": "WebElementWrapper" + }, + ">" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findByPartialLinkText.$1", + "type": "string", + "tags": [], + "label": "linkText", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByPartialLinkText", + "type": "Function", + "tags": [ + "return" + ], + "label": "findAllByPartialLinkText", + "description": [ + "\nGets all elements inside this element matching the given partial link text.\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#findElement\n" + ], + "signature": [ + "(linkText: string, timeout?: number | undefined) => Promise<", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.WebElementWrapper", + "text": "WebElementWrapper" + }, + "[]>" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByPartialLinkText.$1", + "type": "string", + "tags": [], + "label": "linkText", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.findAllByPartialLinkText.$2", + "type": "number", + "tags": [], + "label": "timeout", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.waitForDeletedByCssSelector", + "type": "Function", + "tags": [ + "return" + ], + "label": "waitForDeletedByCssSelector", + "description": [ + "\nWaits for all elements inside this element matching the given CSS selector to be destroyed.\n" + ], + "signature": [ + "(selector: string, implicitTimeout?: number) => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.waitForDeletedByCssSelector.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.waitForDeletedByCssSelector.$2", + "type": "number", + "tags": [], + "label": "implicitTimeout", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.scrollIntoView", + "type": "Function", + "tags": [ + "return" + ], + "label": "scrollIntoView", + "description": [ + "\nScroll the element into view\n" + ], + "signature": [ + "(scrollIntoViewOptions?: ScrollIntoViewOptions | undefined) => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.scrollIntoView.$1", + "type": "Object", + "tags": [], + "label": "scrollIntoViewOptions", + "description": [], + "signature": [ + "ScrollIntoViewOptions | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.scrollIntoViewIfNecessary", + "type": "Function", + "tags": [ + "nonstandard", + "return" + ], + "label": "scrollIntoViewIfNecessary", + "description": [ + "\nScroll the element into view if it is not already, avoiding the fixed header if necessary\nThis method is a variation of the scrollIntoView method, where we only scroll into an element\nif it is not part of the \"scrollable view\".\nThis implies a specific behavior, since the \"scrollable view\" of the view is identified by\nthe `document.scrollingElement`, which always results to the html or body tag.\n\nUse cases:\n- An element (a section, a footer) is not visible in the whole page and we need to scroll into it.\n- An element is covered by the fixed header and we need to scroll into it ensuring is not covered.\n\nIn case you have a scrollable list smaller that the size of the HTML document and you need\nto scroll into an element of that list, prefer using the `.scrollIntoView` method.\n" + ], + "signature": [ + "(topOffsetOrOptions?: number | { topOffset?: number | undefined; bottomOffset?: number | undefined; } | undefined) => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.scrollIntoViewIfNecessary.$1", + "type": "CompoundType", + "tags": [], + "label": "topOffsetOrOptions", + "description": [], + "signature": [ + "number | { topOffset?: number | undefined; bottomOffset?: number | undefined; } | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.parseDomContent", + "type": "Function", + "tags": [ + "nonstandard", + "return" + ], + "label": "parseDomContent", + "description": [ + "\nGets element innerHTML and wrap it up with cheerio\n" + ], + "signature": [ + "() => Promise<", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerioStatic", + "text": "CustomCheerioStatic" + }, + ">" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.WebElementWrapper.takeScreenshot", + "type": "Function", + "tags": [], + "label": "takeScreenshot", + "description": [ + "\nCreates the screenshot of the element\n" + ], + "signature": [ + "() => Promise" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], "functions": [], - "interfaces": [], - "enums": [], + "interfaces": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio", + "type": "Interface", + "tags": [], + "label": "CustomCheerio", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.Unnamed", + "type": "IndexSignature", + "tags": [], + "label": "[index: number]: Element", + "description": [], + "signature": [ + "[index: number]: cheerio.Element" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.length", + "type": "number", + "tags": [], + "label": "length", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.attr", + "type": "Function", + "tags": [], + "label": "attr", + "description": [], + "signature": [ + "{ (): { [attr: string]: string; }; (name: string): string; (name: string, value: any): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.attr", + "type": "Function", + "tags": [], + "label": "attr", + "description": [], + "signature": [ + "{ (): { [attr: string]: string; }; (name: string): string; (name: string, value: any): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.attr.$1", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.attr", + "type": "Function", + "tags": [], + "label": "attr", + "description": [], + "signature": [ + "{ (): { [attr: string]: string; }; (name: string): string; (name: string, value: any): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.attr.$1", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.attr.$2", + "type": "Any", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.data", + "type": "Function", + "tags": [], + "label": "data", + "description": [], + "signature": [ + "{ (): any; (name: string): any; (name: string, value: any): any; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.data", + "type": "Function", + "tags": [], + "label": "data", + "description": [], + "signature": [ + "{ (): any; (name: string): any; (name: string, value: any): any; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.data.$1", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.data", + "type": "Function", + "tags": [], + "label": "data", + "description": [], + "signature": [ + "{ (): any; (name: string): any; (name: string, value: any): any; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.data.$1", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.data.$2", + "type": "Any", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.val", + "type": "Function", + "tags": [], + "label": "val", + "description": [], + "signature": [ + "{ (): string; (value: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.val", + "type": "Function", + "tags": [], + "label": "val", + "description": [], + "signature": [ + "{ (): string; (value: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.val.$1", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.removeAttr", + "type": "Function", + "tags": [], + "label": "removeAttr", + "description": [], + "signature": [ + "(name: string) => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.removeAttr.$1", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.has", + "type": "Function", + "tags": [], + "label": "has", + "description": [], + "signature": [ + "{ (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.has.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.has", + "type": "Function", + "tags": [], + "label": "has", + "description": [], + "signature": [ + "{ (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.has.$1", + "type": "CompoundType", + "tags": [], + "label": "element", + "description": [], + "signature": [ + "cheerio.Element" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.hasClass", + "type": "Function", + "tags": [], + "label": "hasClass", + "description": [], + "signature": [ + "(className: string) => boolean" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.hasClass.$1", + "type": "string", + "tags": [], + "label": "className", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.addClass", + "type": "Function", + "tags": [], + "label": "addClass", + "description": [], + "signature": [ + "(classNames: string) => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.addClass.$1", + "type": "string", + "tags": [], + "label": "classNames", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.removeClass", + "type": "Function", + "tags": [], + "label": "removeClass", + "description": [], + "signature": [ + "{ (): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (className: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (func: (index: number, className: string) => string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.removeClass", + "type": "Function", + "tags": [], + "label": "removeClass", + "description": [], + "signature": [ + "{ (): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (className: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (func: (index: number, className: string) => string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.removeClass.$1", + "type": "string", + "tags": [], + "label": "className", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.removeClass", + "type": "Function", + "tags": [], + "label": "removeClass", + "description": [], + "signature": [ + "{ (): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (className: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (func: (index: number, className: string) => string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.removeClass.$1", + "type": "Function", + "tags": [], + "label": "func", + "description": [], + "signature": [ + "(index: number, className: string) => string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.toggleClass", + "type": "Function", + "tags": [], + "label": "toggleClass", + "description": [], + "signature": [ + "{ (className: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (className: string, toggleSwitch: boolean): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (toggleSwitch?: boolean | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (func: (index: number, className: string, toggleSwitch: boolean) => string, toggleSwitch?: boolean | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.toggleClass.$1", + "type": "string", + "tags": [], + "label": "className", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.toggleClass", + "type": "Function", + "tags": [], + "label": "toggleClass", + "description": [], + "signature": [ + "{ (className: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (className: string, toggleSwitch: boolean): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (toggleSwitch?: boolean | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (func: (index: number, className: string, toggleSwitch: boolean) => string, toggleSwitch?: boolean | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.toggleClass.$1", + "type": "string", + "tags": [], + "label": "className", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.toggleClass.$2", + "type": "boolean", + "tags": [], + "label": "toggleSwitch", + "description": [], + "signature": [ + "boolean" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.toggleClass", + "type": "Function", + "tags": [], + "label": "toggleClass", + "description": [], + "signature": [ + "{ (className: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (className: string, toggleSwitch: boolean): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (toggleSwitch?: boolean | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (func: (index: number, className: string, toggleSwitch: boolean) => string, toggleSwitch?: boolean | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.toggleClass.$1", + "type": "CompoundType", + "tags": [], + "label": "toggleSwitch", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.toggleClass", + "type": "Function", + "tags": [], + "label": "toggleClass", + "description": [], + "signature": [ + "{ (className: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (className: string, toggleSwitch: boolean): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (toggleSwitch?: boolean | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (func: (index: number, className: string, toggleSwitch: boolean) => string, toggleSwitch?: boolean | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.toggleClass.$1", + "type": "Function", + "tags": [], + "label": "func", + "description": [], + "signature": [ + "(index: number, className: string, toggleSwitch: boolean) => string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.toggleClass.$2", + "type": "CompoundType", + "tags": [], + "label": "toggleSwitch", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.is", + "type": "Function", + "tags": [], + "label": "is", + "description": [], + "signature": [ + "{ (selector: string): boolean; (element: cheerio.Element): boolean; (element: cheerio.Element[]): boolean; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): boolean; (func: (index: number, element: cheerio.Element) => boolean): boolean; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.is.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.is", + "type": "Function", + "tags": [], + "label": "is", + "description": [], + "signature": [ + "{ (selector: string): boolean; (element: cheerio.Element): boolean; (element: cheerio.Element[]): boolean; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): boolean; (func: (index: number, element: cheerio.Element) => boolean): boolean; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.is.$1", + "type": "CompoundType", + "tags": [], + "label": "element", + "description": [], + "signature": [ + "cheerio.Element" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.is", + "type": "Function", + "tags": [], + "label": "is", + "description": [], + "signature": [ + "{ (selector: string): boolean; (element: cheerio.Element): boolean; (element: cheerio.Element[]): boolean; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): boolean; (func: (index: number, element: cheerio.Element) => boolean): boolean; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.is.$1", + "type": "Array", + "tags": [], + "label": "element", + "description": [], + "signature": [ + "cheerio.Element[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.is", + "type": "Function", + "tags": [], + "label": "is", + "description": [], + "signature": [ + "{ (selector: string): boolean; (element: cheerio.Element): boolean; (element: cheerio.Element[]): boolean; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): boolean; (func: (index: number, element: cheerio.Element) => boolean): boolean; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.is.$1", + "type": "Object", + "tags": [], + "label": "selection", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.is", + "type": "Function", + "tags": [], + "label": "is", + "description": [], + "signature": [ + "{ (selector: string): boolean; (element: cheerio.Element): boolean; (element: cheerio.Element[]): boolean; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): boolean; (func: (index: number, element: cheerio.Element) => boolean): boolean; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.is.$1", + "type": "Function", + "tags": [], + "label": "func", + "description": [], + "signature": [ + "(index: number, element: cheerio.Element) => boolean" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.serialize", + "type": "Function", + "tags": [], + "label": "serialize", + "description": [], + "signature": [ + "() => string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.serializeArray", + "type": "Function", + "tags": [], + "label": "serializeArray", + "description": [], + "signature": [ + "() => { name: string; value: string; }[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.find", + "type": "Function", + "tags": [], + "label": "find", + "description": [], + "signature": [ + "{ (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.find.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.find", + "type": "Function", + "tags": [], + "label": "find", + "description": [], + "signature": [ + "{ (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.find.$1", + "type": "Object", + "tags": [], + "label": "element", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.parent", + "type": "Function", + "tags": [], + "label": "parent", + "description": [], + "signature": [ + "(selector?: string | undefined) => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.parent.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.parents", + "type": "Function", + "tags": [], + "label": "parents", + "description": [], + "signature": [ + "(selector?: string | undefined) => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.parents.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.parentsUntil", + "type": "Function", + "tags": [], + "label": "parentsUntil", + "description": [], + "signature": [ + "{ (selector?: string | undefined, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.parentsUntil.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.parentsUntil.$2", + "type": "string", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.parentsUntil", + "type": "Function", + "tags": [], + "label": "parentsUntil", + "description": [], + "signature": [ + "{ (selector?: string | undefined, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.parentsUntil.$1", + "type": "CompoundType", + "tags": [], + "label": "element", + "description": [], + "signature": [ + "cheerio.Element" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.parentsUntil.$2", + "type": "string", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.parentsUntil", + "type": "Function", + "tags": [], + "label": "parentsUntil", + "description": [], + "signature": [ + "{ (selector?: string | undefined, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.parentsUntil.$1", + "type": "Object", + "tags": [], + "label": "element", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.parentsUntil.$2", + "type": "string", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prop", + "type": "Function", + "tags": [], + "label": "prop", + "description": [], + "signature": [ + "{ (name: string): any; (name: string, value: any): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prop.$1", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prop", + "type": "Function", + "tags": [], + "label": "prop", + "description": [], + "signature": [ + "{ (name: string): any; (name: string, value: any): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prop.$1", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prop.$2", + "type": "Any", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.closest", + "type": "Function", + "tags": [], + "label": "closest", + "description": [], + "signature": [ + "{ (): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.closest", + "type": "Function", + "tags": [], + "label": "closest", + "description": [], + "signature": [ + "{ (): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.closest.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.next", + "type": "Function", + "tags": [], + "label": "next", + "description": [], + "signature": [ + "(selector?: string | undefined) => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.next.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.nextAll", + "type": "Function", + "tags": [], + "label": "nextAll", + "description": [], + "signature": [ + "{ (): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.nextAll", + "type": "Function", + "tags": [], + "label": "nextAll", + "description": [], + "signature": [ + "{ (): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.nextAll.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.nextUntil", + "type": "Function", + "tags": [], + "label": "nextUntil", + "description": [], + "signature": [ + "{ (selector?: string | undefined, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.nextUntil.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.nextUntil.$2", + "type": "string", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.nextUntil", + "type": "Function", + "tags": [], + "label": "nextUntil", + "description": [], + "signature": [ + "{ (selector?: string | undefined, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.nextUntil.$1", + "type": "CompoundType", + "tags": [], + "label": "element", + "description": [], + "signature": [ + "cheerio.Element" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.nextUntil.$2", + "type": "string", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.nextUntil", + "type": "Function", + "tags": [], + "label": "nextUntil", + "description": [], + "signature": [ + "{ (selector?: string | undefined, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.nextUntil.$1", + "type": "Object", + "tags": [], + "label": "element", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.nextUntil.$2", + "type": "string", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prev", + "type": "Function", + "tags": [], + "label": "prev", + "description": [], + "signature": [ + "(selector?: string | undefined) => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prev.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prevAll", + "type": "Function", + "tags": [], + "label": "prevAll", + "description": [], + "signature": [ + "{ (): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prevAll", + "type": "Function", + "tags": [], + "label": "prevAll", + "description": [], + "signature": [ + "{ (): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prevAll.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prevUntil", + "type": "Function", + "tags": [], + "label": "prevUntil", + "description": [], + "signature": [ + "{ (selector?: string | undefined, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prevUntil.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prevUntil.$2", + "type": "string", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prevUntil", + "type": "Function", + "tags": [], + "label": "prevUntil", + "description": [], + "signature": [ + "{ (selector?: string | undefined, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prevUntil.$1", + "type": "CompoundType", + "tags": [], + "label": "element", + "description": [], + "signature": [ + "cheerio.Element" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prevUntil.$2", + "type": "string", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prevUntil", + "type": "Function", + "tags": [], + "label": "prevUntil", + "description": [], + "signature": [ + "{ (selector?: string | undefined, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element, filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", filter?: string | undefined): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prevUntil.$1", + "type": "Object", + "tags": [], + "label": "element", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prevUntil.$2", + "type": "string", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.slice", + "type": "Function", + "tags": [], + "label": "slice", + "description": [], + "signature": [ + "(start: number, end?: number | undefined) => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.slice.$1", + "type": "number", + "tags": [], + "label": "start", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.slice.$2", + "type": "number", + "tags": [], + "label": "end", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.siblings", + "type": "Function", + "tags": [], + "label": "siblings", + "description": [], + "signature": [ + "(selector?: string | undefined) => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.siblings.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.children", + "type": "Function", + "tags": [], + "label": "children", + "description": [], + "signature": [ + "(selector?: string | undefined) => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.children.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.contents", + "type": "Function", + "tags": [], + "label": "contents", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.each", + "type": "Function", + "tags": [], + "label": "each", + "description": [], + "signature": [ + "(func: (index: number, element: cheerio.Element) => any) => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.each.$1", + "type": "Function", + "tags": [], + "label": "func", + "description": [], + "signature": [ + "(index: number, element: cheerio.Element) => any" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.map", + "type": "Function", + "tags": [], + "label": "map", + "description": [], + "signature": [ + "(func: (index: number, element: cheerio.Element) => any) => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.map.$1", + "type": "Function", + "tags": [], + "label": "func", + "description": [], + "signature": [ + "(index: number, element: cheerio.Element) => any" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.filter", + "type": "Function", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + "{ (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (elements: cheerio.Element[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (func: (index: number, element: cheerio.Element) => boolean): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.filter.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.filter", + "type": "Function", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + "{ (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (elements: cheerio.Element[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (func: (index: number, element: cheerio.Element) => boolean): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.filter.$1", + "type": "Object", + "tags": [], + "label": "selection", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.filter", + "type": "Function", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + "{ (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (elements: cheerio.Element[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (func: (index: number, element: cheerio.Element) => boolean): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.filter.$1", + "type": "CompoundType", + "tags": [], + "label": "element", + "description": [], + "signature": [ + "cheerio.Element" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.filter", + "type": "Function", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + "{ (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (elements: cheerio.Element[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (func: (index: number, element: cheerio.Element) => boolean): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.filter.$1", + "type": "Array", + "tags": [], + "label": "elements", + "description": [], + "signature": [ + "cheerio.Element[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.filter", + "type": "Function", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + "{ (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (elements: cheerio.Element[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (func: (index: number, element: cheerio.Element) => boolean): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.filter.$1", + "type": "Function", + "tags": [], + "label": "func", + "description": [], + "signature": [ + "(index: number, element: cheerio.Element) => boolean" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.not", + "type": "Function", + "tags": [], + "label": "not", + "description": [], + "signature": [ + "{ (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (func: (index: number, element: cheerio.Element) => boolean): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.not.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.not", + "type": "Function", + "tags": [], + "label": "not", + "description": [], + "signature": [ + "{ (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (func: (index: number, element: cheerio.Element) => boolean): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.not.$1", + "type": "Object", + "tags": [], + "label": "selection", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.not", + "type": "Function", + "tags": [], + "label": "not", + "description": [], + "signature": [ + "{ (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (func: (index: number, element: cheerio.Element) => boolean): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.not.$1", + "type": "CompoundType", + "tags": [], + "label": "element", + "description": [], + "signature": [ + "cheerio.Element" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.not", + "type": "Function", + "tags": [], + "label": "not", + "description": [], + "signature": [ + "{ (selector: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (func: (index: number, element: cheerio.Element) => boolean): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.not.$1", + "type": "Function", + "tags": [], + "label": "func", + "description": [], + "signature": [ + "(index: number, element: cheerio.Element) => boolean" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.first", + "type": "Function", + "tags": [], + "label": "first", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.last", + "type": "Function", + "tags": [], + "label": "last", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.eq", + "type": "Function", + "tags": [], + "label": "eq", + "description": [], + "signature": [ + "(index: number) => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.eq.$1", + "type": "number", + "tags": [], + "label": "index", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.get", + "type": "Function", + "tags": [], + "label": "get", + "description": [], + "signature": [ + "{ (): any[]; (index: number): any; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.get", + "type": "Function", + "tags": [], + "label": "get", + "description": [], + "signature": [ + "{ (): any[]; (index: number): any; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.get.$1", + "type": "number", + "tags": [], + "label": "index", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.index", + "type": "Function", + "tags": [], + "label": "index", + "description": [], + "signature": [ + "{ (): number; (selector: string): number; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): number; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.index", + "type": "Function", + "tags": [], + "label": "index", + "description": [], + "signature": [ + "{ (): number; (selector: string): number; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): number; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.index.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.index", + "type": "Function", + "tags": [], + "label": "index", + "description": [], + "signature": [ + "{ (): number; (selector: string): number; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): number; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.index.$1", + "type": "Object", + "tags": [], + "label": "selection", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.end", + "type": "Function", + "tags": [], + "label": "end", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.add", + "type": "Function", + "tags": [], + "label": "add", + "description": [], + "signature": [ + "{ (selectorOrHtml: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selector: string, context: Document): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (elements: cheerio.Element[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.add.$1", + "type": "string", + "tags": [], + "label": "selectorOrHtml", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.add", + "type": "Function", + "tags": [], + "label": "add", + "description": [], + "signature": [ + "{ (selectorOrHtml: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selector: string, context: Document): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (elements: cheerio.Element[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.add.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.add.$2", + "type": "Object", + "tags": [], + "label": "context", + "description": [], + "signature": [ + "Document" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.add", + "type": "Function", + "tags": [], + "label": "add", + "description": [], + "signature": [ + "{ (selectorOrHtml: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selector: string, context: Document): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (elements: cheerio.Element[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.add.$1", + "type": "CompoundType", + "tags": [], + "label": "element", + "description": [], + "signature": [ + "cheerio.Element" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.add", + "type": "Function", + "tags": [], + "label": "add", + "description": [], + "signature": [ + "{ (selectorOrHtml: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selector: string, context: Document): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (elements: cheerio.Element[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.add.$1", + "type": "Array", + "tags": [], + "label": "elements", + "description": [], + "signature": [ + "cheerio.Element[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.add", + "type": "Function", + "tags": [], + "label": "add", + "description": [], + "signature": [ + "{ (selectorOrHtml: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selector: string, context: Document): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (element: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (elements: cheerio.Element[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (selection: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.add.$1", + "type": "Object", + "tags": [], + "label": "selection", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.addBack", + "type": "Function", + "tags": [], + "label": "addBack", + "description": [], + "signature": [ + "{ (): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (filter: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.addBack", + "type": "Function", + "tags": [], + "label": "addBack", + "description": [], + "signature": [ + "{ (): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (filter: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.addBack.$1", + "type": "string", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.appendTo", + "type": "Function", + "tags": [], + "label": "appendTo", + "description": [], + "signature": [ + "(target: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ") => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.appendTo.$1", + "type": "Object", + "tags": [], + "label": "target", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prependTo", + "type": "Function", + "tags": [], + "label": "prependTo", + "description": [], + "signature": [ + "(target: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ") => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prependTo.$1", + "type": "Object", + "tags": [], + "label": "target", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.append", + "type": "Function", + "tags": [], + "label": "append", + "description": [], + "signature": [ + "{ (content: string, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document[], ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.append.$1", + "type": "string", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.append.$2", + "type": "Array", + "tags": [], + "label": "contents", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.append", + "type": "Function", + "tags": [], + "label": "append", + "description": [], + "signature": [ + "{ (content: string, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document[], ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.append.$1", + "type": "Object", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "Document" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.append.$2", + "type": "Array", + "tags": [], + "label": "contents", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.append", + "type": "Function", + "tags": [], + "label": "append", + "description": [], + "signature": [ + "{ (content: string, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document[], ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.append.$1", + "type": "Array", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "Document[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.append.$2", + "type": "Array", + "tags": [], + "label": "contents", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.append", + "type": "Function", + "tags": [], + "label": "append", + "description": [], + "signature": [ + "{ (content: string, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document[], ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.append.$1", + "type": "Object", + "tags": [], + "label": "content", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.append.$2", + "type": "Array", + "tags": [], + "label": "contents", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prepend", + "type": "Function", + "tags": [], + "label": "prepend", + "description": [], + "signature": [ + "{ (content: string, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document[], ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prepend.$1", + "type": "string", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prepend.$2", + "type": "Array", + "tags": [], + "label": "contents", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prepend", + "type": "Function", + "tags": [], + "label": "prepend", + "description": [], + "signature": [ + "{ (content: string, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document[], ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prepend.$1", + "type": "Object", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "Document" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prepend.$2", + "type": "Array", + "tags": [], + "label": "contents", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prepend", + "type": "Function", + "tags": [], + "label": "prepend", + "description": [], + "signature": [ + "{ (content: string, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document[], ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prepend.$1", + "type": "Array", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "Document[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prepend.$2", + "type": "Array", + "tags": [], + "label": "contents", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prepend", + "type": "Function", + "tags": [], + "label": "prepend", + "description": [], + "signature": [ + "{ (content: string, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document[], ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prepend.$1", + "type": "Object", + "tags": [], + "label": "content", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.prepend.$2", + "type": "Array", + "tags": [], + "label": "contents", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.after", + "type": "Function", + "tags": [], + "label": "after", + "description": [], + "signature": [ + "{ (content: string, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document[], ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.after.$1", + "type": "string", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.after.$2", + "type": "Array", + "tags": [], + "label": "contents", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.after", + "type": "Function", + "tags": [], + "label": "after", + "description": [], + "signature": [ + "{ (content: string, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document[], ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.after.$1", + "type": "Object", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "Document" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.after.$2", + "type": "Array", + "tags": [], + "label": "contents", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.after", + "type": "Function", + "tags": [], + "label": "after", + "description": [], + "signature": [ + "{ (content: string, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document[], ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.after.$1", + "type": "Array", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "Document[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.after.$2", + "type": "Array", + "tags": [], + "label": "contents", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.after", + "type": "Function", + "tags": [], + "label": "after", + "description": [], + "signature": [ + "{ (content: string, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document[], ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.after.$1", + "type": "Object", + "tags": [], + "label": "content", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.after.$2", + "type": "Array", + "tags": [], + "label": "contents", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.insertAfter", + "type": "Function", + "tags": [], + "label": "insertAfter", + "description": [], + "signature": [ + "{ (content: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.insertAfter.$1", + "type": "string", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.insertAfter", + "type": "Function", + "tags": [], + "label": "insertAfter", + "description": [], + "signature": [ + "{ (content: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.insertAfter.$1", + "type": "Object", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "Document" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.insertAfter", + "type": "Function", + "tags": [], + "label": "insertAfter", + "description": [], + "signature": [ + "{ (content: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.insertAfter.$1", + "type": "Object", + "tags": [], + "label": "content", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.before", + "type": "Function", + "tags": [], + "label": "before", + "description": [], + "signature": [ + "{ (content: string, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document[], ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.before.$1", + "type": "string", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.before.$2", + "type": "Array", + "tags": [], + "label": "contents", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.before", + "type": "Function", + "tags": [], + "label": "before", + "description": [], + "signature": [ + "{ (content: string, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document[], ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.before.$1", + "type": "Object", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "Document" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.before.$2", + "type": "Array", + "tags": [], + "label": "contents", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.before", + "type": "Function", + "tags": [], + "label": "before", + "description": [], + "signature": [ + "{ (content: string, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document[], ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.before.$1", + "type": "Array", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "Document[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.before.$2", + "type": "Array", + "tags": [], + "label": "contents", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.before", + "type": "Function", + "tags": [], + "label": "before", + "description": [], + "signature": [ + "{ (content: string, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document, ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document[], ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", ...contents: any[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.before.$1", + "type": "Object", + "tags": [], + "label": "content", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.before.$2", + "type": "Array", + "tags": [], + "label": "contents", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.insertBefore", + "type": "Function", + "tags": [], + "label": "insertBefore", + "description": [], + "signature": [ + "{ (content: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.insertBefore.$1", + "type": "string", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.insertBefore", + "type": "Function", + "tags": [], + "label": "insertBefore", + "description": [], + "signature": [ + "{ (content: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.insertBefore.$1", + "type": "Object", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "Document" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.insertBefore", + "type": "Function", + "tags": [], + "label": "insertBefore", + "description": [], + "signature": [ + "{ (content: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.insertBefore.$1", + "type": "Object", + "tags": [], + "label": "content", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.remove", + "type": "Function", + "tags": [], + "label": "remove", + "description": [], + "signature": [ + "(selector?: string | undefined) => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.remove.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.replaceWith", + "type": "Function", + "tags": [], + "label": "replaceWith", + "description": [], + "signature": [ + "{ (content: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: cheerio.Element[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: () => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.replaceWith.$1", + "type": "string", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.replaceWith", + "type": "Function", + "tags": [], + "label": "replaceWith", + "description": [], + "signature": [ + "{ (content: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: cheerio.Element[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: () => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.replaceWith.$1", + "type": "CompoundType", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "cheerio.Element" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.replaceWith", + "type": "Function", + "tags": [], + "label": "replaceWith", + "description": [], + "signature": [ + "{ (content: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: cheerio.Element[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: () => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.replaceWith.$1", + "type": "Array", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "cheerio.Element[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.replaceWith", + "type": "Function", + "tags": [], + "label": "replaceWith", + "description": [], + "signature": [ + "{ (content: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: cheerio.Element[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: () => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.replaceWith.$1", + "type": "Object", + "tags": [], + "label": "content", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.replaceWith", + "type": "Function", + "tags": [], + "label": "replaceWith", + "description": [], + "signature": [ + "{ (content: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: cheerio.Element): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: cheerio.Element[]): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: () => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.replaceWith.$1", + "type": "Function", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.empty", + "type": "Function", + "tags": [], + "label": "empty", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.html", + "type": "Function", + "tags": [], + "label": "html", + "description": [], + "signature": [ + "{ (): string | null; (html: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.html", + "type": "Function", + "tags": [], + "label": "html", + "description": [], + "signature": [ + "{ (): string | null; (html: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.html.$1", + "type": "string", + "tags": [], + "label": "html", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.text", + "type": "Function", + "tags": [], + "label": "text", + "description": [], + "signature": [ + "{ (): string; (text: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.text", + "type": "Function", + "tags": [], + "label": "text", + "description": [], + "signature": [ + "{ (): string; (text: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.text.$1", + "type": "string", + "tags": [], + "label": "text", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.wrap", + "type": "Function", + "tags": [], + "label": "wrap", + "description": [], + "signature": [ + "{ (content: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.wrap.$1", + "type": "string", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.wrap", + "type": "Function", + "tags": [], + "label": "wrap", + "description": [], + "signature": [ + "{ (content: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.wrap.$1", + "type": "Object", + "tags": [], + "label": "content", + "description": [], + "signature": [ + "Document" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.wrap", + "type": "Function", + "tags": [], + "label": "wrap", + "description": [], + "signature": [ + "{ (content: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: Document): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (content: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.wrap.$1", + "type": "Object", + "tags": [], + "label": "content", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css", + "type": "Function", + "tags": [], + "label": "css", + "description": [], + "signature": [ + "{ (propertyName: string): string; (propertyNames: string[]): string[]; (propertyName: string, value: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, value: number): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, func: (index: number, value: string) => string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, func: (index: number, value: string) => number): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (properties: Record): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css.$1", + "type": "string", + "tags": [], + "label": "propertyName", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css", + "type": "Function", + "tags": [], + "label": "css", + "description": [], + "signature": [ + "{ (propertyName: string): string; (propertyNames: string[]): string[]; (propertyName: string, value: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, value: number): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, func: (index: number, value: string) => string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, func: (index: number, value: string) => number): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (properties: Record): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css.$1", + "type": "Array", + "tags": [], + "label": "propertyNames", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css", + "type": "Function", + "tags": [], + "label": "css", + "description": [], + "signature": [ + "{ (propertyName: string): string; (propertyNames: string[]): string[]; (propertyName: string, value: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, value: number): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, func: (index: number, value: string) => string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, func: (index: number, value: string) => number): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (properties: Record): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css.$1", + "type": "string", + "tags": [], + "label": "propertyName", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css.$2", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css", + "type": "Function", + "tags": [], + "label": "css", + "description": [], + "signature": [ + "{ (propertyName: string): string; (propertyNames: string[]): string[]; (propertyName: string, value: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, value: number): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, func: (index: number, value: string) => string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, func: (index: number, value: string) => number): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (properties: Record): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css.$1", + "type": "string", + "tags": [], + "label": "propertyName", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css.$2", + "type": "number", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css", + "type": "Function", + "tags": [], + "label": "css", + "description": [], + "signature": [ + "{ (propertyName: string): string; (propertyNames: string[]): string[]; (propertyName: string, value: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, value: number): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, func: (index: number, value: string) => string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, func: (index: number, value: string) => number): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (properties: Record): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css.$1", + "type": "string", + "tags": [], + "label": "propertyName", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css.$2", + "type": "Function", + "tags": [], + "label": "func", + "description": [], + "signature": [ + "(index: number, value: string) => string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css", + "type": "Function", + "tags": [], + "label": "css", + "description": [], + "signature": [ + "{ (propertyName: string): string; (propertyNames: string[]): string[]; (propertyName: string, value: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, value: number): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, func: (index: number, value: string) => string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, func: (index: number, value: string) => number): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (properties: Record): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css.$1", + "type": "string", + "tags": [], + "label": "propertyName", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css.$2", + "type": "Function", + "tags": [], + "label": "func", + "description": [], + "signature": [ + "(index: number, value: string) => number" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css", + "type": "Function", + "tags": [], + "label": "css", + "description": [], + "signature": [ + "{ (propertyName: string): string; (propertyNames: string[]): string[]; (propertyName: string, value: string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, value: number): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, func: (index: number, value: string) => string): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (propertyName: string, func: (index: number, value: string) => number): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; (properties: Record): ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.css.$1", + "type": "Object", + "tags": [], + "label": "properties", + "description": [], + "signature": [ + "Record" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.clone", + "type": "Function", + "tags": [], + "label": "clone", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.toArray", + "type": "Function", + "tags": [], + "label": "toArray", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + "[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.findTestSubjects", + "type": "Function", + "tags": [], + "label": "findTestSubjects", + "description": [], + "signature": [ + "(selector: string) => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.findTestSubjects.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.findTestSubject", + "type": "Function", + "tags": [], + "label": "findTestSubject", + "description": [], + "signature": [ + "(selector: string) => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerio.findTestSubject.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic", + "type": "Interface", + "tags": [], + "label": "CustomCheerioStatic", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerioStatic", + "text": "CustomCheerioStatic" + }, + " extends CheerioSelector" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.xml", + "type": "Function", + "tags": [], + "label": "xml", + "description": [], + "signature": [ + "() => string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.root", + "type": "Function", + "tags": [], + "label": "root", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.contains", + "type": "Function", + "tags": [], + "label": "contains", + "description": [], + "signature": [ + "(container: cheerio.Element, contained: cheerio.Element) => boolean" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.contains.$1", + "type": "CompoundType", + "tags": [], + "label": "container", + "description": [], + "signature": [ + "cheerio.Element" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.contains.$2", + "type": "CompoundType", + "tags": [], + "label": "contained", + "description": [], + "signature": [ + "cheerio.Element" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.parseHTML", + "type": "Function", + "tags": [], + "label": "parseHTML", + "description": [], + "signature": [ + "(data: string, context?: Document | undefined, keepScripts?: boolean | undefined) => Document[]" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.parseHTML.$1", + "type": "string", + "tags": [], + "label": "data", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.parseHTML.$2", + "type": "Object", + "tags": [], + "label": "context", + "description": [], + "signature": [ + "Document | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.parseHTML.$3", + "type": "CompoundType", + "tags": [], + "label": "keepScripts", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.html", + "type": "Function", + "tags": [], + "label": "html", + "description": [], + "signature": [ + "{ (options?: cheerio.CheerioParserOptions | undefined): string; (selector: string, options?: cheerio.CheerioParserOptions | undefined): string; (element: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", options?: cheerio.CheerioParserOptions | undefined): string; (element: cheerio.Element, options?: cheerio.CheerioParserOptions | undefined): string; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.html.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "cheerio.CheerioParserOptions | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.html", + "type": "Function", + "tags": [], + "label": "html", + "description": [], + "signature": [ + "{ (options?: cheerio.CheerioParserOptions | undefined): string; (selector: string, options?: cheerio.CheerioParserOptions | undefined): string; (element: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", options?: cheerio.CheerioParserOptions | undefined): string; (element: cheerio.Element, options?: cheerio.CheerioParserOptions | undefined): string; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.html.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.html.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "cheerio.CheerioParserOptions | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.html", + "type": "Function", + "tags": [], + "label": "html", + "description": [], + "signature": [ + "{ (options?: cheerio.CheerioParserOptions | undefined): string; (selector: string, options?: cheerio.CheerioParserOptions | undefined): string; (element: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", options?: cheerio.CheerioParserOptions | undefined): string; (element: cheerio.Element, options?: cheerio.CheerioParserOptions | undefined): string; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.html.$1", + "type": "Object", + "tags": [], + "label": "element", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.html.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "cheerio.CheerioParserOptions | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.html", + "type": "Function", + "tags": [], + "label": "html", + "description": [], + "signature": [ + "{ (options?: cheerio.CheerioParserOptions | undefined): string; (selector: string, options?: cheerio.CheerioParserOptions | undefined): string; (element: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + }, + ", options?: cheerio.CheerioParserOptions | undefined): string; (element: cheerio.Element, options?: cheerio.CheerioParserOptions | undefined): string; }" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.html.$1", + "type": "CompoundType", + "tags": [], + "label": "element", + "description": [], + "signature": [ + "cheerio.Element" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.html.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "cheerio.CheerioParserOptions | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.findTestSubjects", + "type": "Function", + "tags": [], + "label": "findTestSubjects", + "description": [], + "signature": [ + "(selector: string) => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.findTestSubjects.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.findTestSubject", + "type": "Function", + "tags": [], + "label": "findTestSubject", + "description": [], + "signature": [ + "(selector: string) => ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.CustomCheerio", + "text": "CustomCheerio" + } + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.CustomCheerioStatic.findTestSubject.$1", + "type": "string", + "tags": [], + "label": "selector", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/custom_cheerio_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NetworkOptions", + "type": "Interface", + "tags": [], + "label": "NetworkOptions", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NetworkOptions.offline", + "type": "boolean", + "tags": [], + "label": "offline", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NetworkOptions.latency", + "type": "number", + "tags": [], + "label": "latency", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NetworkOptions.download_throughput", + "type": "number", + "tags": [], + "label": "download_throughput", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NetworkOptions.upload_throughput", + "type": "number", + "tags": [], + "label": "upload_throughput", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.TimeoutOpt", + "type": "Interface", + "tags": [], + "label": "TimeoutOpt", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.TimeoutOpt.timeout", + "type": "number", + "tags": [], + "label": "timeout", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.Browsers", + "type": "Enum", + "tags": [], + "label": "Browsers", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/browsers.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], "misc": [ { "parentPluginId": "@kbn/ftr-common-functional-ui-services", @@ -31,13 +10002,75 @@ "description": [], "signature": [ { - "pluginId": "@kbn/test", + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GenericFtrProviderContext", + "text": "GenericFtrProviderContext" + }, + "<{ retry: typeof ", + { + "pluginId": "@kbn/ftr-common-functional-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", + "section": "def-common.RetryService", + "text": "RetryService" + }, + "; retryOnStale: ({ getService }: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", "scope": "common", - "docId": "kibKbnTestPluginApi", - "section": "def-common.GenericFtrProviderContext", - "text": "GenericFtrProviderContext" + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => { (fn: () => Promise): Promise; wrap(fn: (...args: Args) => Promise): (...args: Args) => Promise; }; __webdriver__: ({ getService }: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => Promise<{ driver: ", + "WebDriver", + "; browserType: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.Browsers", + "text": "Browsers" + }, + "; consoleLog$: ", + "Observable", + "<{ message: string; level: string; }>; }>; find: (ctx: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => Promise<", + "FindService", + ">; }, {}, ProvidedTypeMap<{ retry: typeof ", + { + "pluginId": "@kbn/ftr-common-functional-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", + "section": "def-common.RetryService", + "text": "RetryService" + }, + "; retryOnStale: ({ getService }: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" }, - "<{ retryOnStale: ({ getService }: ", + ") => { (fn: () => Promise): Promise; wrap(fn: (...args: Args) => Promise): (...args: Args) => Promise; }; __webdriver__: ({ getService }: ", { "pluginId": "@kbn/ftr-common-functional-ui-services", "scope": "common", @@ -45,7 +10078,19 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { (fn: () => Promise): Promise; wrap(fn: (...args: Args) => Promise): (...args: Args) => Promise; }; }, {}, ProvidedTypeMap<{ retryOnStale: ({ getService }: ", + ") => Promise<{ driver: ", + "WebDriver", + "; browserType: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.Browsers", + "text": "Browsers" + }, + "; consoleLog$: ", + "Observable", + "<{ message: string; level: string; }>; }>; find: (ctx: ", { "pluginId": "@kbn/ftr-common-functional-ui-services", "scope": "common", @@ -53,15 +10098,346 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { (fn: () => Promise): Promise; wrap(fn: (...args: Args) => Promise): (...args: Args) => Promise; }; }>, ProvidedTypeMap<{}>>" + ") => Promise<", + "FindService", + ">; }>, ProvidedTypeMap<{}>>" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/ftr_provider_context.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NetworkProfile", + "type": "Type", + "tags": [], + "label": "NetworkProfile", + "description": [], + "signature": [ + "\"NO_THROTTLING\" | \"FAST_3G\" | \"SLOW_3G\" | \"OFFLINE\" | \"CLOUD_USER\"" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES", + "type": "Object", + "tags": [], + "label": "NETWORK_PROFILES", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.NO_THROTTLING", + "type": "Object", + "tags": [], + "label": "NO_THROTTLING", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.NO_THROTTLING.offline", + "type": "boolean", + "tags": [], + "label": "offline", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.NO_THROTTLING.latency", + "type": "number", + "tags": [], + "label": "latency", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.NO_THROTTLING.download_throughput", + "type": "number", + "tags": [], + "label": "download_throughput", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.NO_THROTTLING.upload_throughput", + "type": "number", + "tags": [], + "label": "upload_throughput", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.FAST_3G", + "type": "Object", + "tags": [], + "label": "FAST_3G", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.FAST_3G.offline", + "type": "boolean", + "tags": [], + "label": "offline", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.FAST_3G.latency", + "type": "number", + "tags": [], + "label": "latency", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.FAST_3G.download_throughput", + "type": "number", + "tags": [], + "label": "download_throughput", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.FAST_3G.upload_throughput", + "type": "number", + "tags": [], + "label": "upload_throughput", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.SLOW_3G", + "type": "Object", + "tags": [], + "label": "SLOW_3G", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.SLOW_3G.offline", + "type": "boolean", + "tags": [], + "label": "offline", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.SLOW_3G.latency", + "type": "number", + "tags": [], + "label": "latency", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.SLOW_3G.download_throughput", + "type": "number", + "tags": [], + "label": "download_throughput", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.SLOW_3G.upload_throughput", + "type": "number", + "tags": [], + "label": "upload_throughput", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.OFFLINE", + "type": "Object", + "tags": [], + "label": "OFFLINE", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.OFFLINE.offline", + "type": "boolean", + "tags": [], + "label": "offline", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.OFFLINE.latency", + "type": "number", + "tags": [], + "label": "latency", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.OFFLINE.download_throughput", + "type": "number", + "tags": [], + "label": "download_throughput", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.OFFLINE.upload_throughput", + "type": "number", + "tags": [], + "label": "upload_throughput", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.CLOUD_USER", + "type": "Object", + "tags": [], + "label": "CLOUD_USER", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.CLOUD_USER.offline", + "type": "boolean", + "tags": [], + "label": "offline", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.CLOUD_USER.latency", + "type": "number", + "tags": [], + "label": "latency", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.CLOUD_USER.download_throughput", + "type": "number", + "tags": [], + "label": "download_throughput", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.NETWORK_PROFILES.CLOUD_USER.upload_throughput", + "type": "number", + "tags": [], + "label": "upload_throughput", + "description": [], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/network_profiles.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } ], - "path": "packages/kbn-ftr-common-functional-ui-services/services/ftr_provider_context.ts", - "deprecated": false, - "trackAdoption": false, "initialIsOpen": false - } - ], - "objects": [ + }, { "parentPluginId": "@kbn/ftr-common-functional-ui-services", "id": "def-common.services", @@ -111,7 +10487,69 @@ "section": "def-common.GenericFtrProviderContext", "text": "GenericFtrProviderContext" }, - "<{ retryOnStale: ({ getService }: ", + "<{ retry: typeof ", + { + "pluginId": "@kbn/ftr-common-functional-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", + "section": "def-common.RetryService", + "text": "RetryService" + }, + "; retryOnStale: ({ getService }: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => { (fn: () => Promise): Promise; wrap(fn: (...args: Args) => Promise): (...args: Args) => Promise; }; __webdriver__: ({ getService }: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => Promise<{ driver: ", + "WebDriver", + "; browserType: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.Browsers", + "text": "Browsers" + }, + "; consoleLog$: ", + "Observable", + "<{ message: string; level: string; }>; }>; find: (ctx: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => Promise<", + "FindService", + ">; }, {}, ProvidedTypeMap<{ retry: typeof ", + { + "pluginId": "@kbn/ftr-common-functional-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", + "section": "def-common.RetryService", + "text": "RetryService" + }, + "; retryOnStale: ({ getService }: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => { (fn: () => Promise): Promise; wrap(fn: (...args: Args) => Promise): (...args: Args) => Promise; }; __webdriver__: ({ getService }: ", { "pluginId": "@kbn/ftr-common-functional-ui-services", "scope": "common", @@ -119,7 +10557,19 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { (fn: () => Promise): Promise; wrap(fn: (...args: Args) => Promise): (...args: Args) => Promise; }; }, {}, ProvidedTypeMap<{ retryOnStale: ({ getService }: ", + ") => Promise<{ driver: ", + "WebDriver", + "; browserType: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.Browsers", + "text": "Browsers" + }, + "; consoleLog$: ", + "Observable", + "<{ message: string; level: string; }>; }>; find: (ctx: ", { "pluginId": "@kbn/ftr-common-functional-ui-services", "scope": "common", @@ -127,13 +10577,305 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { (fn: () => Promise): Promise; wrap(fn: (...args: Args) => Promise): (...args: Args) => Promise; }; }>, ProvidedTypeMap<{}>>" + ") => Promise<", + "FindService", + ">; }>, ProvidedTypeMap<{}>>" ], "path": "packages/kbn-ftr-common-functional-ui-services/services/retry_on_stale.ts", "deprecated": false, "trackAdoption": false } ] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.services.__webdriver__", + "type": "Function", + "tags": [], + "label": "__webdriver__", + "description": [], + "signature": [ + "({ getService }: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => Promise<{ driver: ", + "WebDriver", + "; browserType: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.Browsers", + "text": "Browsers" + }, + "; consoleLog$: ", + "Observable", + "<{ message: string; level: string; }>; }>" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/all.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.services.__webdriver__.$1", + "type": "Object", + "tags": [], + "label": "__0", + "description": [], + "signature": [ + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GenericFtrProviderContext", + "text": "GenericFtrProviderContext" + }, + "<{ retry: typeof ", + { + "pluginId": "@kbn/ftr-common-functional-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", + "section": "def-common.RetryService", + "text": "RetryService" + }, + "; retryOnStale: ({ getService }: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => { (fn: () => Promise): Promise; wrap(fn: (...args: Args) => Promise): (...args: Args) => Promise; }; __webdriver__: ({ getService }: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => Promise<{ driver: ", + "WebDriver", + "; browserType: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.Browsers", + "text": "Browsers" + }, + "; consoleLog$: ", + "Observable", + "<{ message: string; level: string; }>; }>; find: (ctx: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => Promise<", + "FindService", + ">; }, {}, ProvidedTypeMap<{ retry: typeof ", + { + "pluginId": "@kbn/ftr-common-functional-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", + "section": "def-common.RetryService", + "text": "RetryService" + }, + "; retryOnStale: ({ getService }: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => { (fn: () => Promise): Promise; wrap(fn: (...args: Args) => Promise): (...args: Args) => Promise; }; __webdriver__: ({ getService }: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => Promise<{ driver: ", + "WebDriver", + "; browserType: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.Browsers", + "text": "Browsers" + }, + "; consoleLog$: ", + "Observable", + "<{ message: string; level: string; }>; }>; find: (ctx: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => Promise<", + "FindService", + ">; }>, ProvidedTypeMap<{}>>" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/remote/remote.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.services.find", + "type": "Function", + "tags": [], + "label": "find", + "description": [], + "signature": [ + "(ctx: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => Promise<", + "FindService", + ">" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/all.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-ui-services", + "id": "def-common.services.find.$1", + "type": "Object", + "tags": [], + "label": "ctx", + "description": [], + "signature": [ + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GenericFtrProviderContext", + "text": "GenericFtrProviderContext" + }, + "<{ retry: typeof ", + { + "pluginId": "@kbn/ftr-common-functional-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", + "section": "def-common.RetryService", + "text": "RetryService" + }, + "; retryOnStale: ({ getService }: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => { (fn: () => Promise): Promise; wrap(fn: (...args: Args) => Promise): (...args: Args) => Promise; }; __webdriver__: ({ getService }: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => Promise<{ driver: ", + "WebDriver", + "; browserType: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.Browsers", + "text": "Browsers" + }, + "; consoleLog$: ", + "Observable", + "<{ message: string; level: string; }>; }>; find: (ctx: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => Promise<", + "FindService", + ">; }, {}, ProvidedTypeMap<{ retry: typeof ", + { + "pluginId": "@kbn/ftr-common-functional-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", + "section": "def-common.RetryService", + "text": "RetryService" + }, + "; retryOnStale: ({ getService }: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => { (fn: () => Promise): Promise; wrap(fn: (...args: Args) => Promise): (...args: Args) => Promise; }; __webdriver__: ({ getService }: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => Promise<{ driver: ", + "WebDriver", + "; browserType: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.Browsers", + "text": "Browsers" + }, + "; consoleLog$: ", + "Observable", + "<{ message: string; level: string; }>; }>; find: (ctx: ", + { + "pluginId": "@kbn/ftr-common-functional-ui-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalUiServicesPluginApi", + "section": "def-common.FtrProviderContext", + "text": "FtrProviderContext" + }, + ") => Promise<", + "FindService", + ">; }>, ProvidedTypeMap<{}>>" + ], + "path": "packages/kbn-ftr-common-functional-ui-services/services/find.ts", + "deprecated": false, + "trackAdoption": false + } + ] } ], "initialIsOpen": false diff --git a/api_docs/kbn_ftr_common_functional_ui_services.mdx b/api_docs/kbn_ftr_common_functional_ui_services.mdx index 5ae37e8d16e56..0462d908e9c32 100644 --- a/api_docs/kbn_ftr_common_functional_ui_services.mdx +++ b/api_docs/kbn_ftr_common_functional_ui_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-ui-services title: "@kbn/ftr-common-functional-ui-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-ui-services plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-ui-services'] --- import kbnFtrCommonFunctionalUiServicesObj from './kbn_ftr_common_functional_ui_services.devdocs.json'; @@ -21,13 +21,22 @@ Contact [@elastic/appex-qa](https://github.com/orgs/elastic/teams/appex-qa) for | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 4 | 0 | 4 | 0 | +| 435 | 3 | 400 | 1 | ## Common ### Objects +### Classes + + +### Interfaces + + +### Enums + + ### Consts, variables and types diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index 36eafb28920c1..6de650b834e42 100644 --- a/api_docs/kbn_generate.mdx +++ b/api_docs/kbn_generate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate title: "@kbn/generate" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_generate_console_definitions.mdx b/api_docs/kbn_generate_console_definitions.mdx index c1df6a5359777..6a42e84834c09 100644 --- a/api_docs/kbn_generate_console_definitions.mdx +++ b/api_docs/kbn_generate_console_definitions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-console-definitions title: "@kbn/generate-console-definitions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-console-definitions plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-console-definitions'] --- import kbnGenerateConsoleDefinitionsObj from './kbn_generate_console_definitions.devdocs.json'; diff --git a/api_docs/kbn_generate_csv.mdx b/api_docs/kbn_generate_csv.mdx index 7bac3ecd7910f..9bb02531f5623 100644 --- a/api_docs/kbn_generate_csv.mdx +++ b/api_docs/kbn_generate_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-csv title: "@kbn/generate-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-csv plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index db5cdc5bfb7da..164703f1c67fc 100644 --- a/api_docs/kbn_guided_onboarding.mdx +++ b/api_docs/kbn_guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-guided-onboarding title: "@kbn/guided-onboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/guided-onboarding plugin -date: 2024-01-04 +date: 2024-01-05 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 6a0befe70ba7f..589a9a4b0d095 100644 --- a/api_docs/kbn_handlebars.mdx +++ b/api_docs/kbn_handlebars.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-handlebars title: "@kbn/handlebars" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/handlebars plugin -date: 2024-01-04 +date: 2024-01-05 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 bb37a568b1ec5..4ae37ede28201 100644 --- a/api_docs/kbn_hapi_mocks.mdx +++ b/api_docs/kbn_hapi_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-hapi-mocks title: "@kbn/hapi-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/hapi-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 627e55d7366ab..ed4112af4b5c0 100644 --- a/api_docs/kbn_health_gateway_server.mdx +++ b/api_docs/kbn_health_gateway_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-health-gateway-server title: "@kbn/health-gateway-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/health-gateway-server plugin -date: 2024-01-04 +date: 2024-01-05 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 441e0efe22fd7..cb2f6b7600b42 100644 --- a/api_docs/kbn_home_sample_data_card.mdx +++ b/api_docs/kbn_home_sample_data_card.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-card title: "@kbn/home-sample-data-card" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-card plugin -date: 2024-01-04 +date: 2024-01-05 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 6799d3dd72d8a..4ce220fd843db 100644 --- a/api_docs/kbn_home_sample_data_tab.mdx +++ b/api_docs/kbn_home_sample_data_tab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-tab title: "@kbn/home-sample-data-tab" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-tab plugin -date: 2024-01-04 +date: 2024-01-05 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 8a55b88394817..2d89ab1962b22 100644 --- a/api_docs/kbn_i18n.mdx +++ b/api_docs/kbn_i18n.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n title: "@kbn/i18n" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n plugin -date: 2024-01-04 +date: 2024-01-05 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 11fa0001cf29a..c585b16a07e40 100644 --- a/api_docs/kbn_i18n_react.mdx +++ b/api_docs/kbn_i18n_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n-react title: "@kbn/i18n-react" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n-react plugin -date: 2024-01-04 +date: 2024-01-05 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 ec1fb89e48854..2df53cd7c60bc 100644 --- a/api_docs/kbn_import_resolver.mdx +++ b/api_docs/kbn_import_resolver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-import-resolver title: "@kbn/import-resolver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/import-resolver plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_infra_forge.mdx b/api_docs/kbn_infra_forge.mdx index 7f40747ccdcba..65a3c9801acf2 100644 --- a/api_docs/kbn_infra_forge.mdx +++ b/api_docs/kbn_infra_forge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-infra-forge title: "@kbn/infra-forge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/infra-forge plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/infra-forge'] --- import kbnInfraForgeObj from './kbn_infra_forge.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index 6ac0d16ef0a88..1ca1131298dc3 100644 --- a/api_docs/kbn_interpreter.mdx +++ b/api_docs/kbn_interpreter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-interpreter title: "@kbn/interpreter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/interpreter plugin -date: 2024-01-04 +date: 2024-01-05 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 75987734e69fd..c2e410c6fcf88 100644 --- a/api_docs/kbn_io_ts_utils.mdx +++ b/api_docs/kbn_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-io-ts-utils title: "@kbn/io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/io-ts-utils plugin -date: 2024-01-04 +date: 2024-01-05 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 9e823e2397576..ff2f8c4ab99a6 100644 --- a/api_docs/kbn_jest_serializers.mdx +++ b/api_docs/kbn_jest_serializers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-jest-serializers title: "@kbn/jest-serializers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/jest-serializers plugin -date: 2024-01-04 +date: 2024-01-05 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 8f1a3030fbbb7..b96dc45e7ae7a 100644 --- a/api_docs/kbn_journeys.mdx +++ b/api_docs/kbn_journeys.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-journeys title: "@kbn/journeys" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/journeys plugin -date: 2024-01-04 +date: 2024-01-05 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 c49f1a87109fb..7d530618c92dc 100644 --- a/api_docs/kbn_json_ast.mdx +++ b/api_docs/kbn_json_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-ast title: "@kbn/json-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-ast plugin -date: 2024-01-04 +date: 2024-01-05 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 5f60c54d9642c..45c9a15b7ed21 100644 --- a/api_docs/kbn_kibana_manifest_schema.mdx +++ b/api_docs/kbn_kibana_manifest_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-schema title: "@kbn/kibana-manifest-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-schema plugin -date: 2024-01-04 +date: 2024-01-05 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 324f24f8675e0..ef6c7127fc184 100644 --- a/api_docs/kbn_language_documentation_popover.mdx +++ b/api_docs/kbn_language_documentation_popover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-language-documentation-popover title: "@kbn/language-documentation-popover" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/language-documentation-popover plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/language-documentation-popover'] --- import kbnLanguageDocumentationPopoverObj from './kbn_language_documentation_popover.devdocs.json'; diff --git a/api_docs/kbn_lens_embeddable_utils.mdx b/api_docs/kbn_lens_embeddable_utils.mdx index 545336948dd3e..8fc7964ba9fcc 100644 --- a/api_docs/kbn_lens_embeddable_utils.mdx +++ b/api_docs/kbn_lens_embeddable_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-embeddable-utils title: "@kbn/lens-embeddable-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-embeddable-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-embeddable-utils'] --- import kbnLensEmbeddableUtilsObj from './kbn_lens_embeddable_utils.devdocs.json'; diff --git a/api_docs/kbn_lens_formula_docs.mdx b/api_docs/kbn_lens_formula_docs.mdx index 49d87393a64b1..ada9e5adb714a 100644 --- a/api_docs/kbn_lens_formula_docs.mdx +++ b/api_docs/kbn_lens_formula_docs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-formula-docs title: "@kbn/lens-formula-docs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-formula-docs plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-formula-docs'] --- import kbnLensFormulaDocsObj from './kbn_lens_formula_docs.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index 542f339b089d4..5e0b596c73ec1 100644 --- a/api_docs/kbn_logging.mdx +++ b/api_docs/kbn_logging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging title: "@kbn/logging" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging plugin -date: 2024-01-04 +date: 2024-01-05 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 94d7cca0be296..713ab44ef6d71 100644 --- a/api_docs/kbn_logging_mocks.mdx +++ b/api_docs/kbn_logging_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging-mocks title: "@kbn/logging-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 bc1555c584f97..71d5d1b5bc0f9 100644 --- a/api_docs/kbn_managed_vscode_config.mdx +++ b/api_docs/kbn_managed_vscode_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-vscode-config title: "@kbn/managed-vscode-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-vscode-config plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_management_cards_navigation.mdx b/api_docs/kbn_management_cards_navigation.mdx index 1bdb160fbc40a..cf9d1e9b01b3a 100644 --- a/api_docs/kbn_management_cards_navigation.mdx +++ b/api_docs/kbn_management_cards_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-cards-navigation title: "@kbn/management-cards-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-cards-navigation plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-cards-navigation'] --- import kbnManagementCardsNavigationObj from './kbn_management_cards_navigation.devdocs.json'; diff --git a/api_docs/kbn_management_settings_application.mdx b/api_docs/kbn_management_settings_application.mdx index 19b9ea606ec35..b8c533fcfb580 100644 --- a/api_docs/kbn_management_settings_application.mdx +++ b/api_docs/kbn_management_settings_application.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-application title: "@kbn/management-settings-application" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-application plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-application'] --- import kbnManagementSettingsApplicationObj from './kbn_management_settings_application.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_category.mdx b/api_docs/kbn_management_settings_components_field_category.mdx index affa6056621a0..06ab3a7cc6a2c 100644 --- a/api_docs/kbn_management_settings_components_field_category.mdx +++ b/api_docs/kbn_management_settings_components_field_category.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-category title: "@kbn/management-settings-components-field-category" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-category plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-category'] --- import kbnManagementSettingsComponentsFieldCategoryObj from './kbn_management_settings_components_field_category.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_input.mdx b/api_docs/kbn_management_settings_components_field_input.mdx index 8ee7f834f3c6a..b4bf5e830f939 100644 --- a/api_docs/kbn_management_settings_components_field_input.mdx +++ b/api_docs/kbn_management_settings_components_field_input.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-input title: "@kbn/management-settings-components-field-input" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-input plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-input'] --- import kbnManagementSettingsComponentsFieldInputObj from './kbn_management_settings_components_field_input.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_row.mdx b/api_docs/kbn_management_settings_components_field_row.mdx index 68a0b2989d6d8..4638629c096b6 100644 --- a/api_docs/kbn_management_settings_components_field_row.mdx +++ b/api_docs/kbn_management_settings_components_field_row.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-row title: "@kbn/management-settings-components-field-row" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-row plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-row'] --- import kbnManagementSettingsComponentsFieldRowObj from './kbn_management_settings_components_field_row.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_form.mdx b/api_docs/kbn_management_settings_components_form.mdx index 01813717bb7ba..ade13d0cdbab0 100644 --- a/api_docs/kbn_management_settings_components_form.mdx +++ b/api_docs/kbn_management_settings_components_form.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-form title: "@kbn/management-settings-components-form" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-form plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-form'] --- import kbnManagementSettingsComponentsFormObj from './kbn_management_settings_components_form.devdocs.json'; diff --git a/api_docs/kbn_management_settings_field_definition.mdx b/api_docs/kbn_management_settings_field_definition.mdx index 8c23fe69ea36b..e5d23eca5d4bf 100644 --- a/api_docs/kbn_management_settings_field_definition.mdx +++ b/api_docs/kbn_management_settings_field_definition.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-field-definition title: "@kbn/management-settings-field-definition" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-field-definition plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-field-definition'] --- import kbnManagementSettingsFieldDefinitionObj from './kbn_management_settings_field_definition.devdocs.json'; diff --git a/api_docs/kbn_management_settings_ids.mdx b/api_docs/kbn_management_settings_ids.mdx index a2af9654d6fd7..ef16bc6baa0ed 100644 --- a/api_docs/kbn_management_settings_ids.mdx +++ b/api_docs/kbn_management_settings_ids.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-ids title: "@kbn/management-settings-ids" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-ids plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-ids'] --- import kbnManagementSettingsIdsObj from './kbn_management_settings_ids.devdocs.json'; diff --git a/api_docs/kbn_management_settings_section_registry.mdx b/api_docs/kbn_management_settings_section_registry.mdx index d8c9c2b467eae..8321ebeb4d893 100644 --- a/api_docs/kbn_management_settings_section_registry.mdx +++ b/api_docs/kbn_management_settings_section_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-section-registry title: "@kbn/management-settings-section-registry" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-section-registry plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-section-registry'] --- import kbnManagementSettingsSectionRegistryObj from './kbn_management_settings_section_registry.devdocs.json'; diff --git a/api_docs/kbn_management_settings_types.mdx b/api_docs/kbn_management_settings_types.mdx index 843c1a1a00164..969775d6e6d6f 100644 --- a/api_docs/kbn_management_settings_types.mdx +++ b/api_docs/kbn_management_settings_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-types title: "@kbn/management-settings-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-types plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-types'] --- import kbnManagementSettingsTypesObj from './kbn_management_settings_types.devdocs.json'; diff --git a/api_docs/kbn_management_settings_utilities.mdx b/api_docs/kbn_management_settings_utilities.mdx index 3c816e2185887..7a5b3363f7a30 100644 --- a/api_docs/kbn_management_settings_utilities.mdx +++ b/api_docs/kbn_management_settings_utilities.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-utilities title: "@kbn/management-settings-utilities" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-utilities plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-utilities'] --- import kbnManagementSettingsUtilitiesObj from './kbn_management_settings_utilities.devdocs.json'; diff --git a/api_docs/kbn_management_storybook_config.mdx b/api_docs/kbn_management_storybook_config.mdx index eba599a7e5075..66fd051700142 100644 --- a/api_docs/kbn_management_storybook_config.mdx +++ b/api_docs/kbn_management_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-storybook-config title: "@kbn/management-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-storybook-config plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-storybook-config'] --- import kbnManagementStorybookConfigObj from './kbn_management_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index 1f5342d2c4d1c..4d0bf1385439e 100644 --- a/api_docs/kbn_mapbox_gl.mdx +++ b/api_docs/kbn_mapbox_gl.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mapbox-gl title: "@kbn/mapbox-gl" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mapbox-gl plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_maps_vector_tile_utils.mdx b/api_docs/kbn_maps_vector_tile_utils.mdx index c9bd0585c6686..3d33e69cc4618 100644 --- a/api_docs/kbn_maps_vector_tile_utils.mdx +++ b/api_docs/kbn_maps_vector_tile_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-maps-vector-tile-utils title: "@kbn/maps-vector-tile-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/maps-vector-tile-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/maps-vector-tile-utils'] --- import kbnMapsVectorTileUtilsObj from './kbn_maps_vector_tile_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index 5d2de4f593d7a..7c0c3e82d55c7 100644 --- a/api_docs/kbn_ml_agg_utils.mdx +++ b/api_docs/kbn_ml_agg_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-agg-utils title: "@kbn/ml-agg-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-agg-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-agg-utils'] --- import kbnMlAggUtilsObj from './kbn_ml_agg_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_anomaly_utils.mdx b/api_docs/kbn_ml_anomaly_utils.mdx index 4ae0cd37048f3..81f73e0edfb76 100644 --- a/api_docs/kbn_ml_anomaly_utils.mdx +++ b/api_docs/kbn_ml_anomaly_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-anomaly-utils title: "@kbn/ml-anomaly-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-anomaly-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-anomaly-utils'] --- import kbnMlAnomalyUtilsObj from './kbn_ml_anomaly_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_category_validator.mdx b/api_docs/kbn_ml_category_validator.mdx index 1749b7b94941d..cc4feb403b89f 100644 --- a/api_docs/kbn_ml_category_validator.mdx +++ b/api_docs/kbn_ml_category_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-category-validator title: "@kbn/ml-category-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-category-validator plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-category-validator'] --- import kbnMlCategoryValidatorObj from './kbn_ml_category_validator.devdocs.json'; diff --git a/api_docs/kbn_ml_chi2test.mdx b/api_docs/kbn_ml_chi2test.mdx index 87aa68a02ce1e..4c0c3b7cee8ac 100644 --- a/api_docs/kbn_ml_chi2test.mdx +++ b/api_docs/kbn_ml_chi2test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-chi2test title: "@kbn/ml-chi2test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-chi2test plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-chi2test'] --- import kbnMlChi2testObj from './kbn_ml_chi2test.devdocs.json'; diff --git a/api_docs/kbn_ml_data_frame_analytics_utils.mdx b/api_docs/kbn_ml_data_frame_analytics_utils.mdx index b51e24cfc9e02..57a98f81dfd03 100644 --- a/api_docs/kbn_ml_data_frame_analytics_utils.mdx +++ b/api_docs/kbn_ml_data_frame_analytics_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-frame-analytics-utils title: "@kbn/ml-data-frame-analytics-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-frame-analytics-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-frame-analytics-utils'] --- import kbnMlDataFrameAnalyticsUtilsObj from './kbn_ml_data_frame_analytics_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_data_grid.mdx b/api_docs/kbn_ml_data_grid.mdx index 15704541aba35..7e838f9aa80e0 100644 --- a/api_docs/kbn_ml_data_grid.mdx +++ b/api_docs/kbn_ml_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-grid title: "@kbn/ml-data-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-grid plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-grid'] --- import kbnMlDataGridObj from './kbn_ml_data_grid.devdocs.json'; diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index 7f1d1f24f296b..713ab86eba72a 100644 --- a/api_docs/kbn_ml_date_picker.mdx +++ b/api_docs/kbn_ml_date_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-picker title: "@kbn/ml-date-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-picker plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-picker'] --- import kbnMlDatePickerObj from './kbn_ml_date_picker.devdocs.json'; diff --git a/api_docs/kbn_ml_date_utils.mdx b/api_docs/kbn_ml_date_utils.mdx index 32d332cb36251..531d9689ede3d 100644 --- a/api_docs/kbn_ml_date_utils.mdx +++ b/api_docs/kbn_ml_date_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-utils title: "@kbn/ml-date-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-utils'] --- import kbnMlDateUtilsObj from './kbn_ml_date_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_error_utils.mdx b/api_docs/kbn_ml_error_utils.mdx index 0817c29408526..06d7b83320e3f 100644 --- a/api_docs/kbn_ml_error_utils.mdx +++ b/api_docs/kbn_ml_error_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-error-utils title: "@kbn/ml-error-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-error-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-error-utils'] --- import kbnMlErrorUtilsObj from './kbn_ml_error_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_in_memory_table.mdx b/api_docs/kbn_ml_in_memory_table.mdx index 7b99edefb5d33..b357ace2ee946 100644 --- a/api_docs/kbn_ml_in_memory_table.mdx +++ b/api_docs/kbn_ml_in_memory_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-in-memory-table title: "@kbn/ml-in-memory-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-in-memory-table plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-in-memory-table'] --- import kbnMlInMemoryTableObj from './kbn_ml_in_memory_table.devdocs.json'; diff --git a/api_docs/kbn_ml_is_defined.mdx b/api_docs/kbn_ml_is_defined.mdx index ba7f8df01c943..2e312df561945 100644 --- a/api_docs/kbn_ml_is_defined.mdx +++ b/api_docs/kbn_ml_is_defined.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-defined title: "@kbn/ml-is-defined" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-defined plugin -date: 2024-01-04 +date: 2024-01-05 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 cc3caa796ca3f..d48cdf4046fc5 100644 --- a/api_docs/kbn_ml_is_populated_object.mdx +++ b/api_docs/kbn_ml_is_populated_object.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-populated-object title: "@kbn/ml-is-populated-object" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-populated-object plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-populated-object'] --- import kbnMlIsPopulatedObjectObj from './kbn_ml_is_populated_object.devdocs.json'; diff --git a/api_docs/kbn_ml_kibana_theme.mdx b/api_docs/kbn_ml_kibana_theme.mdx index 2baaadefca37e..4ec1d8121e4c2 100644 --- a/api_docs/kbn_ml_kibana_theme.mdx +++ b/api_docs/kbn_ml_kibana_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-kibana-theme title: "@kbn/ml-kibana-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-kibana-theme plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-kibana-theme'] --- import kbnMlKibanaThemeObj from './kbn_ml_kibana_theme.devdocs.json'; diff --git a/api_docs/kbn_ml_local_storage.mdx b/api_docs/kbn_ml_local_storage.mdx index 9c43a57f9ec49..98ae63d633221 100644 --- a/api_docs/kbn_ml_local_storage.mdx +++ b/api_docs/kbn_ml_local_storage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-local-storage title: "@kbn/ml-local-storage" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-local-storage plugin -date: 2024-01-04 +date: 2024-01-05 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 ea76351c49442..523f7f330185d 100644 --- a/api_docs/kbn_ml_nested_property.mdx +++ b/api_docs/kbn_ml_nested_property.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-nested-property title: "@kbn/ml-nested-property" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-nested-property plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-nested-property'] --- import kbnMlNestedPropertyObj from './kbn_ml_nested_property.devdocs.json'; diff --git a/api_docs/kbn_ml_number_utils.mdx b/api_docs/kbn_ml_number_utils.mdx index 8d5b4fd623e5c..a0f36bfe015a3 100644 --- a/api_docs/kbn_ml_number_utils.mdx +++ b/api_docs/kbn_ml_number_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-number-utils title: "@kbn/ml-number-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-number-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-number-utils'] --- import kbnMlNumberUtilsObj from './kbn_ml_number_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_query_utils.mdx b/api_docs/kbn_ml_query_utils.mdx index c647a2df0a9e5..c5e8f8edace08 100644 --- a/api_docs/kbn_ml_query_utils.mdx +++ b/api_docs/kbn_ml_query_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-query-utils title: "@kbn/ml-query-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-query-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-query-utils'] --- import kbnMlQueryUtilsObj from './kbn_ml_query_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_random_sampler_utils.mdx b/api_docs/kbn_ml_random_sampler_utils.mdx index a841aba311646..d4d831344a17e 100644 --- a/api_docs/kbn_ml_random_sampler_utils.mdx +++ b/api_docs/kbn_ml_random_sampler_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-random-sampler-utils title: "@kbn/ml-random-sampler-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-random-sampler-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-random-sampler-utils'] --- import kbnMlRandomSamplerUtilsObj from './kbn_ml_random_sampler_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_route_utils.mdx b/api_docs/kbn_ml_route_utils.mdx index ccd80736003c1..4551285ea2a57 100644 --- a/api_docs/kbn_ml_route_utils.mdx +++ b/api_docs/kbn_ml_route_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-route-utils title: "@kbn/ml-route-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-route-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-route-utils'] --- import kbnMlRouteUtilsObj from './kbn_ml_route_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_runtime_field_utils.mdx b/api_docs/kbn_ml_runtime_field_utils.mdx index 492263a8f3d01..bee10c0479887 100644 --- a/api_docs/kbn_ml_runtime_field_utils.mdx +++ b/api_docs/kbn_ml_runtime_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-runtime-field-utils title: "@kbn/ml-runtime-field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-runtime-field-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-runtime-field-utils'] --- import kbnMlRuntimeFieldUtilsObj from './kbn_ml_runtime_field_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index f25d70b6cd1f1..9c7000dd9be24 100644 --- a/api_docs/kbn_ml_string_hash.mdx +++ b/api_docs/kbn_ml_string_hash.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-string-hash title: "@kbn/ml-string-hash" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-string-hash plugin -date: 2024-01-04 +date: 2024-01-05 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 a11036a8ec060..44814479857cd 100644 --- a/api_docs/kbn_ml_trained_models_utils.mdx +++ b/api_docs/kbn_ml_trained_models_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-trained-models-utils title: "@kbn/ml-trained-models-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-trained-models-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-trained-models-utils'] --- import kbnMlTrainedModelsUtilsObj from './kbn_ml_trained_models_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_ui_actions.mdx b/api_docs/kbn_ml_ui_actions.mdx index 77579773f2d25..667842156e967 100644 --- a/api_docs/kbn_ml_ui_actions.mdx +++ b/api_docs/kbn_ml_ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-ui-actions title: "@kbn/ml-ui-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-ui-actions plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-ui-actions'] --- import kbnMlUiActionsObj from './kbn_ml_ui_actions.devdocs.json'; diff --git a/api_docs/kbn_ml_url_state.mdx b/api_docs/kbn_ml_url_state.mdx index eb3fc4d159e98..e4f78f9b55ce5 100644 --- a/api_docs/kbn_ml_url_state.mdx +++ b/api_docs/kbn_ml_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-url-state title: "@kbn/ml-url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-url-state plugin -date: 2024-01-04 +date: 2024-01-05 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 af33db98bd479..120703eb8f8e3 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-monaco title: "@kbn/monaco" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/monaco plugin -date: 2024-01-04 +date: 2024-01-05 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 3a7f7718854db..09475095c3a01 100644 --- a/api_docs/kbn_object_versioning.mdx +++ b/api_docs/kbn_object_versioning.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-object-versioning title: "@kbn/object-versioning" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/object-versioning plugin -date: 2024-01-04 +date: 2024-01-05 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 c9745d645c585..e94b1206eb35f 100644 --- a/api_docs/kbn_observability_alert_details.mdx +++ b/api_docs/kbn_observability_alert_details.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alert-details title: "@kbn/observability-alert-details" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alert-details plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alert-details'] --- import kbnObservabilityAlertDetailsObj from './kbn_observability_alert_details.devdocs.json'; diff --git a/api_docs/kbn_observability_alerting_test_data.mdx b/api_docs/kbn_observability_alerting_test_data.mdx index 42a2150e00911..0008d5c38e268 100644 --- a/api_docs/kbn_observability_alerting_test_data.mdx +++ b/api_docs/kbn_observability_alerting_test_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alerting-test-data title: "@kbn/observability-alerting-test-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alerting-test-data plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alerting-test-data'] --- import kbnObservabilityAlertingTestDataObj from './kbn_observability_alerting_test_data.devdocs.json'; diff --git a/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx index b13a5137b825e..84ec788e62c3f 100644 --- a/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx +++ b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-get-padded-alert-time-range-util title: "@kbn/observability-get-padded-alert-time-range-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-get-padded-alert-time-range-util plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-get-padded-alert-time-range-util'] --- import kbnObservabilityGetPaddedAlertTimeRangeUtilObj from './kbn_observability_get_padded_alert_time_range_util.devdocs.json'; diff --git a/api_docs/kbn_openapi_bundler.mdx b/api_docs/kbn_openapi_bundler.mdx index bd8a7f9a511aa..605f12107057a 100644 --- a/api_docs/kbn_openapi_bundler.mdx +++ b/api_docs/kbn_openapi_bundler.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-bundler title: "@kbn/openapi-bundler" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-bundler plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-bundler'] --- import kbnOpenapiBundlerObj from './kbn_openapi_bundler.devdocs.json'; diff --git a/api_docs/kbn_openapi_generator.mdx b/api_docs/kbn_openapi_generator.mdx index f351063dc53f1..b79a5e2986ab7 100644 --- a/api_docs/kbn_openapi_generator.mdx +++ b/api_docs/kbn_openapi_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-generator title: "@kbn/openapi-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-generator plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-generator'] --- import kbnOpenapiGeneratorObj from './kbn_openapi_generator.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index 106de241e3f71..9c6bc1d29b408 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer title: "@kbn/optimizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer plugin -date: 2024-01-04 +date: 2024-01-05 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 3c99f96697c13..6469a938998c6 100644 --- a/api_docs/kbn_optimizer_webpack_helpers.mdx +++ b/api_docs/kbn_optimizer_webpack_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer-webpack-helpers title: "@kbn/optimizer-webpack-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer-webpack-helpers plugin -date: 2024-01-04 +date: 2024-01-05 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 9ec21c688095b..c85afb88f8fde 100644 --- a/api_docs/kbn_osquery_io_ts_types.mdx +++ b/api_docs/kbn_osquery_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-osquery-io-ts-types title: "@kbn/osquery-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/osquery-io-ts-types plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/osquery-io-ts-types'] --- import kbnOsqueryIoTsTypesObj from './kbn_osquery_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_panel_loader.mdx b/api_docs/kbn_panel_loader.mdx index 95b31bd16993f..5022c3172234d 100644 --- a/api_docs/kbn_panel_loader.mdx +++ b/api_docs/kbn_panel_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-panel-loader title: "@kbn/panel-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/panel-loader plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/panel-loader'] --- import kbnPanelLoaderObj from './kbn_panel_loader.devdocs.json'; diff --git a/api_docs/kbn_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index 7bb20cc446e44..db9a30d30413c 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.mdx +++ b/api_docs/kbn_performance_testing_dataset_extractor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-performance-testing-dataset-extractor title: "@kbn/performance-testing-dataset-extractor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/performance-testing-dataset-extractor plugin -date: 2024-01-04 +date: 2024-01-05 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 9a2911c70c02a..00156ca303a8e 100644 --- a/api_docs/kbn_plugin_generator.mdx +++ b/api_docs/kbn_plugin_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-generator title: "@kbn/plugin-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-generator plugin -date: 2024-01-04 +date: 2024-01-05 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 0264711c85004..7f428a6f42bb0 100644 --- a/api_docs/kbn_plugin_helpers.mdx +++ b/api_docs/kbn_plugin_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-helpers title: "@kbn/plugin-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-helpers plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_profiling_utils.mdx b/api_docs/kbn_profiling_utils.mdx index 6f0b23f99b947..1728df95bbb6a 100644 --- a/api_docs/kbn_profiling_utils.mdx +++ b/api_docs/kbn_profiling_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-profiling-utils title: "@kbn/profiling-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/profiling-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/profiling-utils'] --- import kbnProfilingUtilsObj from './kbn_profiling_utils.devdocs.json'; diff --git a/api_docs/kbn_random_sampling.mdx b/api_docs/kbn_random_sampling.mdx index 3f36204f291bd..1a285560c8fcd 100644 --- a/api_docs/kbn_random_sampling.mdx +++ b/api_docs/kbn_random_sampling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-random-sampling title: "@kbn/random-sampling" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/random-sampling plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/random-sampling'] --- import kbnRandomSamplingObj from './kbn_random_sampling.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index ae92727810f60..abdfac7d3d923 100644 --- a/api_docs/kbn_react_field.mdx +++ b/api_docs/kbn_react_field.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-field title: "@kbn/react-field" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-field plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_common.mdx b/api_docs/kbn_react_kibana_context_common.mdx index 752c4a1b3b5ba..3f4c70a79e52e 100644 --- a/api_docs/kbn_react_kibana_context_common.mdx +++ b/api_docs/kbn_react_kibana_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-common title: "@kbn/react-kibana-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-common plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-common'] --- import kbnReactKibanaContextCommonObj from './kbn_react_kibana_context_common.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_render.mdx b/api_docs/kbn_react_kibana_context_render.mdx index 3ab51934192ba..ccd5848f67a07 100644 --- a/api_docs/kbn_react_kibana_context_render.mdx +++ b/api_docs/kbn_react_kibana_context_render.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-render title: "@kbn/react-kibana-context-render" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-render plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-render'] --- import kbnReactKibanaContextRenderObj from './kbn_react_kibana_context_render.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_root.mdx b/api_docs/kbn_react_kibana_context_root.mdx index b428dd102f64e..9207d0cc6b108 100644 --- a/api_docs/kbn_react_kibana_context_root.mdx +++ b/api_docs/kbn_react_kibana_context_root.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-root title: "@kbn/react-kibana-context-root" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-root plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-root'] --- import kbnReactKibanaContextRootObj from './kbn_react_kibana_context_root.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_styled.mdx b/api_docs/kbn_react_kibana_context_styled.mdx index ec8467440e1cc..adab4ef567b74 100644 --- a/api_docs/kbn_react_kibana_context_styled.mdx +++ b/api_docs/kbn_react_kibana_context_styled.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-styled title: "@kbn/react-kibana-context-styled" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-styled plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-styled'] --- import kbnReactKibanaContextStyledObj from './kbn_react_kibana_context_styled.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_theme.mdx b/api_docs/kbn_react_kibana_context_theme.mdx index 425336cc11126..1c46a73334acf 100644 --- a/api_docs/kbn_react_kibana_context_theme.mdx +++ b/api_docs/kbn_react_kibana_context_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-theme title: "@kbn/react-kibana-context-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-theme plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-theme'] --- import kbnReactKibanaContextThemeObj from './kbn_react_kibana_context_theme.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_mount.mdx b/api_docs/kbn_react_kibana_mount.mdx index ae9ad6538f42e..a8cdf13cc1b7b 100644 --- a/api_docs/kbn_react_kibana_mount.mdx +++ b/api_docs/kbn_react_kibana_mount.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-mount title: "@kbn/react-kibana-mount" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-mount plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-mount'] --- import kbnReactKibanaMountObj from './kbn_react_kibana_mount.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index 934e8dc6db220..62b20e0a98ab4 100644 --- a/api_docs/kbn_repo_file_maps.mdx +++ b/api_docs/kbn_repo_file_maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-file-maps title: "@kbn/repo-file-maps" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-file-maps plugin -date: 2024-01-04 +date: 2024-01-05 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 8452c33949f34..e15893489ec43 100644 --- a/api_docs/kbn_repo_linter.mdx +++ b/api_docs/kbn_repo_linter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-linter title: "@kbn/repo-linter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-linter plugin -date: 2024-01-04 +date: 2024-01-05 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 d1b4e65b919cc..aca4a25831e86 100644 --- a/api_docs/kbn_repo_path.mdx +++ b/api_docs/kbn_repo_path.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-path title: "@kbn/repo-path" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-path plugin -date: 2024-01-04 +date: 2024-01-05 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 544e2b0664268..8a30094caf7ba 100644 --- a/api_docs/kbn_repo_source_classifier.mdx +++ b/api_docs/kbn_repo_source_classifier.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-source-classifier title: "@kbn/repo-source-classifier" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-source-classifier plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_reporting_common.mdx b/api_docs/kbn_reporting_common.mdx index 5e307d64f309a..f2cfe051b8fa8 100644 --- a/api_docs/kbn_reporting_common.mdx +++ b/api_docs/kbn_reporting_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-common title: "@kbn/reporting-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-common plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-common'] --- import kbnReportingCommonObj from './kbn_reporting_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv.mdx b/api_docs/kbn_reporting_export_types_csv.mdx index cffea7d370a0f..b1ff7cddfad7f 100644 --- a/api_docs/kbn_reporting_export_types_csv.mdx +++ b/api_docs/kbn_reporting_export_types_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv title: "@kbn/reporting-export-types-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv'] --- import kbnReportingExportTypesCsvObj from './kbn_reporting_export_types_csv.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv_common.mdx b/api_docs/kbn_reporting_export_types_csv_common.mdx index 3c031d6311cba..f4109d758df9f 100644 --- a/api_docs/kbn_reporting_export_types_csv_common.mdx +++ b/api_docs/kbn_reporting_export_types_csv_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv-common title: "@kbn/reporting-export-types-csv-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv-common plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv-common'] --- import kbnReportingExportTypesCsvCommonObj from './kbn_reporting_export_types_csv_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf.mdx b/api_docs/kbn_reporting_export_types_pdf.mdx index a55f05c20655c..f02299934a5dd 100644 --- a/api_docs/kbn_reporting_export_types_pdf.mdx +++ b/api_docs/kbn_reporting_export_types_pdf.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf title: "@kbn/reporting-export-types-pdf" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf'] --- import kbnReportingExportTypesPdfObj from './kbn_reporting_export_types_pdf.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf_common.mdx b/api_docs/kbn_reporting_export_types_pdf_common.mdx index 16068bfc850d3..8af8ba3cbc754 100644 --- a/api_docs/kbn_reporting_export_types_pdf_common.mdx +++ b/api_docs/kbn_reporting_export_types_pdf_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf-common title: "@kbn/reporting-export-types-pdf-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf-common plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf-common'] --- import kbnReportingExportTypesPdfCommonObj from './kbn_reporting_export_types_pdf_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png.mdx b/api_docs/kbn_reporting_export_types_png.mdx index 888ab158d8b78..54ee56dcb94eb 100644 --- a/api_docs/kbn_reporting_export_types_png.mdx +++ b/api_docs/kbn_reporting_export_types_png.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png title: "@kbn/reporting-export-types-png" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png'] --- import kbnReportingExportTypesPngObj from './kbn_reporting_export_types_png.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png_common.mdx b/api_docs/kbn_reporting_export_types_png_common.mdx index edeaa5bcba34a..7cea2352eefdb 100644 --- a/api_docs/kbn_reporting_export_types_png_common.mdx +++ b/api_docs/kbn_reporting_export_types_png_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png-common title: "@kbn/reporting-export-types-png-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png-common plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png-common'] --- import kbnReportingExportTypesPngCommonObj from './kbn_reporting_export_types_png_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_mocks_server.mdx b/api_docs/kbn_reporting_mocks_server.mdx index fd930185f2947..85491a2b203df 100644 --- a/api_docs/kbn_reporting_mocks_server.mdx +++ b/api_docs/kbn_reporting_mocks_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-mocks-server title: "@kbn/reporting-mocks-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-mocks-server plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-mocks-server'] --- import kbnReportingMocksServerObj from './kbn_reporting_mocks_server.devdocs.json'; diff --git a/api_docs/kbn_reporting_public.mdx b/api_docs/kbn_reporting_public.mdx index efc40ca26ab59..1629166e8c757 100644 --- a/api_docs/kbn_reporting_public.mdx +++ b/api_docs/kbn_reporting_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-public title: "@kbn/reporting-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-public plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-public'] --- import kbnReportingPublicObj from './kbn_reporting_public.devdocs.json'; diff --git a/api_docs/kbn_reporting_server.mdx b/api_docs/kbn_reporting_server.mdx index 4c448634c1009..358f2b46ceee0 100644 --- a/api_docs/kbn_reporting_server.mdx +++ b/api_docs/kbn_reporting_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-server title: "@kbn/reporting-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-server plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-server'] --- import kbnReportingServerObj from './kbn_reporting_server.devdocs.json'; diff --git a/api_docs/kbn_resizable_layout.mdx b/api_docs/kbn_resizable_layout.mdx index b30087977bd6a..c0b9efd073b9d 100644 --- a/api_docs/kbn_resizable_layout.mdx +++ b/api_docs/kbn_resizable_layout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-resizable-layout title: "@kbn/resizable-layout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/resizable-layout plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/resizable-layout'] --- import kbnResizableLayoutObj from './kbn_resizable_layout.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index e3d821bf69509..f2262eb5c3f03 100644 --- a/api_docs/kbn_rison.mdx +++ b/api_docs/kbn_rison.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rison title: "@kbn/rison" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rison plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_router_utils.mdx b/api_docs/kbn_router_utils.mdx index 41dd91c10405b..05ce5fffc3fbc 100644 --- a/api_docs/kbn_router_utils.mdx +++ b/api_docs/kbn_router_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-router-utils title: "@kbn/router-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/router-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/router-utils'] --- import kbnRouterUtilsObj from './kbn_router_utils.devdocs.json'; diff --git a/api_docs/kbn_rrule.mdx b/api_docs/kbn_rrule.mdx index d7667564e2673..4e31b1f5d6234 100644 --- a/api_docs/kbn_rrule.mdx +++ b/api_docs/kbn_rrule.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rrule title: "@kbn/rrule" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rrule plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rrule'] --- import kbnRruleObj from './kbn_rrule.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index ba718f93a7ea5..0b65f616203c9 100644 --- a/api_docs/kbn_rule_data_utils.mdx +++ b/api_docs/kbn_rule_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rule-data-utils title: "@kbn/rule-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rule-data-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_saved_objects_settings.mdx b/api_docs/kbn_saved_objects_settings.mdx index 6dde8ce80a6b5..c99b93756f8cb 100644 --- a/api_docs/kbn_saved_objects_settings.mdx +++ b/api_docs/kbn_saved_objects_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-saved-objects-settings title: "@kbn/saved-objects-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/saved-objects-settings plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-objects-settings'] --- import kbnSavedObjectsSettingsObj from './kbn_saved_objects_settings.devdocs.json'; diff --git a/api_docs/kbn_search_api_panels.mdx b/api_docs/kbn_search_api_panels.mdx index a13947e6e5261..051247be85c72 100644 --- a/api_docs/kbn_search_api_panels.mdx +++ b/api_docs/kbn_search_api_panels.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-panels title: "@kbn/search-api-panels" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-panels plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-panels'] --- import kbnSearchApiPanelsObj from './kbn_search_api_panels.devdocs.json'; diff --git a/api_docs/kbn_search_connectors.mdx b/api_docs/kbn_search_connectors.mdx index 87f07895068e2..f0f0fb76dac2a 100644 --- a/api_docs/kbn_search_connectors.mdx +++ b/api_docs/kbn_search_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-connectors title: "@kbn/search-connectors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-connectors plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-connectors'] --- import kbnSearchConnectorsObj from './kbn_search_connectors.devdocs.json'; diff --git a/api_docs/kbn_search_errors.mdx b/api_docs/kbn_search_errors.mdx index 6436525cb6a0b..e623995ddec52 100644 --- a/api_docs/kbn_search_errors.mdx +++ b/api_docs/kbn_search_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-errors title: "@kbn/search-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-errors plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-errors'] --- import kbnSearchErrorsObj from './kbn_search_errors.devdocs.json'; diff --git a/api_docs/kbn_search_index_documents.mdx b/api_docs/kbn_search_index_documents.mdx index be8ab42529bc2..d1ca218b8c1f3 100644 --- a/api_docs/kbn_search_index_documents.mdx +++ b/api_docs/kbn_search_index_documents.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-index-documents title: "@kbn/search-index-documents" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-index-documents plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-index-documents'] --- import kbnSearchIndexDocumentsObj from './kbn_search_index_documents.devdocs.json'; diff --git a/api_docs/kbn_search_response_warnings.mdx b/api_docs/kbn_search_response_warnings.mdx index 7fdb3a3cf28fe..6cb31ef0814de 100644 --- a/api_docs/kbn_search_response_warnings.mdx +++ b/api_docs/kbn_search_response_warnings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-response-warnings title: "@kbn/search-response-warnings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-response-warnings plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-response-warnings'] --- import kbnSearchResponseWarningsObj from './kbn_search_response_warnings.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_common.mdx b/api_docs/kbn_security_plugin_types_common.mdx index dbee323f97b17..f422a3f537b5f 100644 --- a/api_docs/kbn_security_plugin_types_common.mdx +++ b/api_docs/kbn_security_plugin_types_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-common title: "@kbn/security-plugin-types-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-common plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-common'] --- import kbnSecurityPluginTypesCommonObj from './kbn_security_plugin_types_common.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_public.mdx b/api_docs/kbn_security_plugin_types_public.mdx index 98b7d98ee4725..9554c4323a80a 100644 --- a/api_docs/kbn_security_plugin_types_public.mdx +++ b/api_docs/kbn_security_plugin_types_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-public title: "@kbn/security-plugin-types-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-public plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-public'] --- import kbnSecurityPluginTypesPublicObj from './kbn_security_plugin_types_public.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_server.mdx b/api_docs/kbn_security_plugin_types_server.mdx index e0f56bc22e011..e7aa4d3a2dd0c 100644 --- a/api_docs/kbn_security_plugin_types_server.mdx +++ b/api_docs/kbn_security_plugin_types_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-server title: "@kbn/security-plugin-types-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-server plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-server'] --- import kbnSecurityPluginTypesServerObj from './kbn_security_plugin_types_server.devdocs.json'; diff --git a/api_docs/kbn_security_solution_features.mdx b/api_docs/kbn_security_solution_features.mdx index 2fbb7e118c612..9ee6d05d0319a 100644 --- a/api_docs/kbn_security_solution_features.mdx +++ b/api_docs/kbn_security_solution_features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-features title: "@kbn/security-solution-features" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-features plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-features'] --- import kbnSecuritySolutionFeaturesObj from './kbn_security_solution_features.devdocs.json'; diff --git a/api_docs/kbn_security_solution_navigation.mdx b/api_docs/kbn_security_solution_navigation.mdx index 92e8e8344b2b6..c1b27ac7e22ca 100644 --- a/api_docs/kbn_security_solution_navigation.mdx +++ b/api_docs/kbn_security_solution_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-navigation title: "@kbn/security-solution-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-navigation plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-navigation'] --- import kbnSecuritySolutionNavigationObj from './kbn_security_solution_navigation.devdocs.json'; diff --git a/api_docs/kbn_security_solution_side_nav.mdx b/api_docs/kbn_security_solution_side_nav.mdx index aff5bd1085fa8..e8d753976dbb2 100644 --- a/api_docs/kbn_security_solution_side_nav.mdx +++ b/api_docs/kbn_security_solution_side_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-side-nav title: "@kbn/security-solution-side-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-side-nav plugin -date: 2024-01-04 +date: 2024-01-05 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 dc21480479027..5987e154ad976 100644 --- a/api_docs/kbn_security_solution_storybook_config.mdx +++ b/api_docs/kbn_security_solution_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-storybook-config title: "@kbn/security-solution-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-storybook-config plugin -date: 2024-01-04 +date: 2024-01-05 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 7163dac06cdc2..c00585e7e584d 100644 --- a/api_docs/kbn_securitysolution_autocomplete.mdx +++ b/api_docs/kbn_securitysolution_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-autocomplete title: "@kbn/securitysolution-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-autocomplete plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_data_table.mdx b/api_docs/kbn_securitysolution_data_table.mdx index 90937af245e19..31edbe0e987bf 100644 --- a/api_docs/kbn_securitysolution_data_table.mdx +++ b/api_docs/kbn_securitysolution_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-data-table title: "@kbn/securitysolution-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-data-table plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-data-table'] --- import kbnSecuritysolutionDataTableObj from './kbn_securitysolution_data_table.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_ecs.mdx b/api_docs/kbn_securitysolution_ecs.mdx index 51e74190ac751..79ae0889e9b56 100644 --- a/api_docs/kbn_securitysolution_ecs.mdx +++ b/api_docs/kbn_securitysolution_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-ecs title: "@kbn/securitysolution-ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-ecs plugin -date: 2024-01-04 +date: 2024-01-05 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 17a40ed54bda2..e2d8ecabdd015 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-es-utils plugin -date: 2024-01-04 +date: 2024-01-05 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 b2afeec510c3c..f3d16f98cfe50 100644 --- a/api_docs/kbn_securitysolution_exception_list_components.mdx +++ b/api_docs/kbn_securitysolution_exception_list_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-exception-list-components title: "@kbn/securitysolution-exception-list-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-exception-list-components plugin -date: 2024-01-04 +date: 2024-01-05 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 db37eb84d8666..9f5e7ab288089 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: 2024-01-04 +date: 2024-01-05 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 0854b53299222..72daa43ab655d 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-hook-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-hook-utils'] --- import kbnSecuritysolutionHookUtilsObj from './kbn_securitysolution_hook_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx index acb3294dcff1b..1fec8a6afab41 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-alerting-types title: "@kbn/securitysolution-io-ts-alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-alerting-types'] --- import kbnSecuritysolutionIoTsAlertingTypesObj from './kbn_securitysolution_io_ts_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index ea3f440adbbeb..a3bc207155a34 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-list-types title: "@kbn/securitysolution-io-ts-list-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-list-types plugin -date: 2024-01-04 +date: 2024-01-05 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 4e888725a1da8..f267d2864ebb5 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-types plugin -date: 2024-01-04 +date: 2024-01-05 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 0ffb44db27367..cca115723befe 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-utils plugin -date: 2024-01-04 +date: 2024-01-05 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 40e6da5004cc5..3004e887c712d 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-api plugin -date: 2024-01-04 +date: 2024-01-05 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 18f0cf1ae0ee2..9ef0c846b50eb 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-constants plugin -date: 2024-01-04 +date: 2024-01-05 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 2a3347f55bae6..f3422437f90ea 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-hooks plugin -date: 2024-01-04 +date: 2024-01-05 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 c1ee608bb1db2..641c80338bae4 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-utils plugin -date: 2024-01-04 +date: 2024-01-05 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 afa1e118ebf3e..e0b25aa2b53ea 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-rules plugin -date: 2024-01-04 +date: 2024-01-05 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 a87fc0b2ac0ed..861b75ea630ba 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-t-grid plugin -date: 2024-01-04 +date: 2024-01-05 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 95f3463571774..4d3732c8fd04d 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-utils plugin -date: 2024-01-04 +date: 2024-01-05 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 ae4b50cd3bb4a..435496895bfa2 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-http-tools plugin -date: 2024-01-04 +date: 2024-01-05 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 937fee8f57568..e602b89e617b1 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_serverless_common_settings.mdx b/api_docs/kbn_serverless_common_settings.mdx index f81861d2b7a22..c77f381d416dc 100644 --- a/api_docs/kbn_serverless_common_settings.mdx +++ b/api_docs/kbn_serverless_common_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-common-settings title: "@kbn/serverless-common-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-common-settings plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-common-settings'] --- import kbnServerlessCommonSettingsObj from './kbn_serverless_common_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_observability_settings.mdx b/api_docs/kbn_serverless_observability_settings.mdx index ae38e144c548d..def8a59b63c0b 100644 --- a/api_docs/kbn_serverless_observability_settings.mdx +++ b/api_docs/kbn_serverless_observability_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-observability-settings title: "@kbn/serverless-observability-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-observability-settings plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-observability-settings'] --- import kbnServerlessObservabilitySettingsObj from './kbn_serverless_observability_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_project_switcher.mdx b/api_docs/kbn_serverless_project_switcher.mdx index 2f55b792e84bf..8b03d326266bc 100644 --- a/api_docs/kbn_serverless_project_switcher.mdx +++ b/api_docs/kbn_serverless_project_switcher.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-project-switcher title: "@kbn/serverless-project-switcher" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-project-switcher plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-project-switcher'] --- import kbnServerlessProjectSwitcherObj from './kbn_serverless_project_switcher.devdocs.json'; diff --git a/api_docs/kbn_serverless_search_settings.mdx b/api_docs/kbn_serverless_search_settings.mdx index c6dc4f07ec729..05330095c4f34 100644 --- a/api_docs/kbn_serverless_search_settings.mdx +++ b/api_docs/kbn_serverless_search_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-search-settings title: "@kbn/serverless-search-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-search-settings plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-search-settings'] --- import kbnServerlessSearchSettingsObj from './kbn_serverless_search_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_security_settings.mdx b/api_docs/kbn_serverless_security_settings.mdx index 83ebdf1d77e17..7ec53585281d3 100644 --- a/api_docs/kbn_serverless_security_settings.mdx +++ b/api_docs/kbn_serverless_security_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-security-settings title: "@kbn/serverless-security-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-security-settings plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-security-settings'] --- import kbnServerlessSecuritySettingsObj from './kbn_serverless_security_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_storybook_config.mdx b/api_docs/kbn_serverless_storybook_config.mdx index ec1bab55da237..09a17afeb930c 100644 --- a/api_docs/kbn_serverless_storybook_config.mdx +++ b/api_docs/kbn_serverless_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-storybook-config title: "@kbn/serverless-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-storybook-config plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-storybook-config'] --- import kbnServerlessStorybookConfigObj from './kbn_serverless_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index 5431f9e167731..823411fdbf8fe 100644 --- a/api_docs/kbn_shared_svg.mdx +++ b/api_docs/kbn_shared_svg.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-svg title: "@kbn/shared-svg" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-svg plugin -date: 2024-01-04 +date: 2024-01-05 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 066131a53df68..c409b690c6456 100644 --- a/api_docs/kbn_shared_ux_avatar_solution.mdx +++ b/api_docs/kbn_shared_ux_avatar_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-solution title: "@kbn/shared-ux-avatar-solution" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-solution plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-solution'] --- import kbnSharedUxAvatarSolutionObj from './kbn_shared_ux_avatar_solution.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx index 3938867793590..cac9a71252c5b 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen title: "@kbn/shared-ux-button-exit-full-screen" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen'] --- import kbnSharedUxButtonExitFullScreenObj from './kbn_shared_ux_button_exit_full_screen.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index ef44ec1d7e587..88dded75428d6 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-toolbar plugin -date: 2024-01-04 +date: 2024-01-05 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 c3f456f227f0d..aa75fb31f0aae 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data title: "@kbn/shared-ux-card-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data plugin -date: 2024-01-04 +date: 2024-01-05 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 5d15ab603ca6c..6f7b65aac95ba 100644 --- a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data-mocks title: "@kbn/shared-ux-card-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data-mocks plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_chrome_navigation.mdx b/api_docs/kbn_shared_ux_chrome_navigation.mdx index bc6f88412940d..5d17a765d2304 100644 --- a/api_docs/kbn_shared_ux_chrome_navigation.mdx +++ b/api_docs/kbn_shared_ux_chrome_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-chrome-navigation title: "@kbn/shared-ux-chrome-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-chrome-navigation plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-chrome-navigation'] --- import kbnSharedUxChromeNavigationObj from './kbn_shared_ux_chrome_navigation.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_error_boundary.mdx b/api_docs/kbn_shared_ux_error_boundary.mdx index 54073921400a3..d78f20c30eafc 100644 --- a/api_docs/kbn_shared_ux_error_boundary.mdx +++ b/api_docs/kbn_shared_ux_error_boundary.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-error-boundary title: "@kbn/shared-ux-error-boundary" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-error-boundary plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-error-boundary'] --- import kbnSharedUxErrorBoundaryObj from './kbn_shared_ux_error_boundary.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index bc71b9ad9324d..d64d3da11302b 100644 --- a/api_docs/kbn_shared_ux_file_context.mdx +++ b/api_docs/kbn_shared_ux_file_context.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-context title: "@kbn/shared-ux-file-context" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-context plugin -date: 2024-01-04 +date: 2024-01-05 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 5bf4b8888bcf7..33f63c702108c 100644 --- a/api_docs/kbn_shared_ux_file_image.mdx +++ b/api_docs/kbn_shared_ux_file_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image title: "@kbn/shared-ux-file-image" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image plugin -date: 2024-01-04 +date: 2024-01-05 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 b0657728c183f..a76fa0df487e8 100644 --- a/api_docs/kbn_shared_ux_file_image_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_image_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image-mocks title: "@kbn/shared-ux-file-image-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 a3c5b0c967b45..683855969b416 100644 --- a/api_docs/kbn_shared_ux_file_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-mocks title: "@kbn/shared-ux-file-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 f4a8ac64778b2..55fa022e43351 100644 --- a/api_docs/kbn_shared_ux_file_picker.mdx +++ b/api_docs/kbn_shared_ux_file_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-picker title: "@kbn/shared-ux-file-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-picker plugin -date: 2024-01-04 +date: 2024-01-05 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 5a36f4e70f4b7..40068d1b30a11 100644 --- a/api_docs/kbn_shared_ux_file_types.mdx +++ b/api_docs/kbn_shared_ux_file_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-types title: "@kbn/shared-ux-file-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-types plugin -date: 2024-01-04 +date: 2024-01-05 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 214d49cacc56c..52af2912e4994 100644 --- a/api_docs/kbn_shared_ux_file_upload.mdx +++ b/api_docs/kbn_shared_ux_file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-upload title: "@kbn/shared-ux-file-upload" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-upload plugin -date: 2024-01-04 +date: 2024-01-05 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 55a174557b7ba..329b66574c6ce 100644 --- a/api_docs/kbn_shared_ux_file_util.mdx +++ b/api_docs/kbn_shared_ux_file_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-util title: "@kbn/shared-ux-file-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-util plugin -date: 2024-01-04 +date: 2024-01-05 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 dfd6ed1999a23..c120f8c1c345e 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app title: "@kbn/shared-ux-link-redirect-app" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app plugin -date: 2024-01-04 +date: 2024-01-05 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 8352f4b366f71..9a7ce12cf8acd 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app-mocks title: "@kbn/shared-ux-link-redirect-app-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 099046c2f5f2d..4c79a852c3905 100644 --- a/api_docs/kbn_shared_ux_markdown.mdx +++ b/api_docs/kbn_shared_ux_markdown.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown title: "@kbn/shared-ux-markdown" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown plugin -date: 2024-01-04 +date: 2024-01-05 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 99d0a0fe58b55..1a12232e0b2f4 100644 --- a/api_docs/kbn_shared_ux_markdown_mocks.mdx +++ b/api_docs/kbn_shared_ux_markdown_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown-mocks title: "@kbn/shared-ux-markdown-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 93d84a4d60904..d9d3673bd3bb7 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data title: "@kbn/shared-ux-page-analytics-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data plugin -date: 2024-01-04 +date: 2024-01-05 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 b7b893d353ce1..97714d7b54229 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data-mocks title: "@kbn/shared-ux-page-analytics-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 b2e2082bf682c..6600b947fe2e1 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data title: "@kbn/shared-ux-page-kibana-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data plugin -date: 2024-01-04 +date: 2024-01-05 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 7886c18d6e140..aa6aaa03ebf86 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data-mocks title: "@kbn/shared-ux-page-kibana-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 6a5df38fdb42b..87657ae6f1907 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template title: "@kbn/shared-ux-page-kibana-template" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template plugin -date: 2024-01-04 +date: 2024-01-05 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 cfc33d1476587..6bf28994f3b3a 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template-mocks title: "@kbn/shared-ux-page-kibana-template-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 9039fd3d9ddad..737dabad08b5b 100644 --- a/api_docs/kbn_shared_ux_page_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data title: "@kbn/shared-ux-page-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data plugin -date: 2024-01-04 +date: 2024-01-05 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 6b510fb7bb1d7..525aef5e95ca3 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config title: "@kbn/shared-ux-page-no-data-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config plugin -date: 2024-01-04 +date: 2024-01-05 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 f71530cb9c8ea..17c1929004f3d 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config-mocks title: "@kbn/shared-ux-page-no-data-config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 538aa87c13941..40a7869373d11 100644 --- a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-mocks title: "@kbn/shared-ux-page-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 40b76ca9599e6..891feab6e4df6 100644 --- a/api_docs/kbn_shared_ux_page_solution_nav.mdx +++ b/api_docs/kbn_shared_ux_page_solution_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-solution-nav title: "@kbn/shared-ux-page-solution-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-solution-nav plugin -date: 2024-01-04 +date: 2024-01-05 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 b5c76b7869f4a..caa3acb9fbf2f 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views title: "@kbn/shared-ux-prompt-no-data-views" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views plugin -date: 2024-01-04 +date: 2024-01-05 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 40ea019a88d4e..d3bafe9772ef9 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views-mocks title: "@kbn/shared-ux-prompt-no-data-views-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 38f5104395b42..a7d8129d6771e 100644 --- a/api_docs/kbn_shared_ux_prompt_not_found.mdx +++ b/api_docs/kbn_shared_ux_prompt_not_found.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-not-found title: "@kbn/shared-ux-prompt-not-found" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-not-found plugin -date: 2024-01-04 +date: 2024-01-05 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 339bdfe6f8a4f..bab20d3ae174b 100644 --- a/api_docs/kbn_shared_ux_router.mdx +++ b/api_docs/kbn_shared_ux_router.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router title: "@kbn/shared-ux-router" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router plugin -date: 2024-01-04 +date: 2024-01-05 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 7389373f01590..2dbcdccbdae4c 100644 --- a/api_docs/kbn_shared_ux_router_mocks.mdx +++ b/api_docs/kbn_shared_ux_router_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router-mocks title: "@kbn/shared-ux-router-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router-mocks plugin -date: 2024-01-04 +date: 2024-01-05 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 f791535672973..e5ceb4b1d0b33 100644 --- a/api_docs/kbn_shared_ux_storybook_config.mdx +++ b/api_docs/kbn_shared_ux_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-config title: "@kbn/shared-ux-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-config plugin -date: 2024-01-04 +date: 2024-01-05 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 3f305dba05a87..6c3d9e5432ce5 100644 --- a/api_docs/kbn_shared_ux_storybook_mock.mdx +++ b/api_docs/kbn_shared_ux_storybook_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-mock title: "@kbn/shared-ux-storybook-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-mock plugin -date: 2024-01-04 +date: 2024-01-05 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 6eefeea597adf..66229d6d6b75b 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-utility plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_slo_schema.mdx b/api_docs/kbn_slo_schema.mdx index ebc02e018b762..91fe7f815a779 100644 --- a/api_docs/kbn_slo_schema.mdx +++ b/api_docs/kbn_slo_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-slo-schema title: "@kbn/slo-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/slo-schema plugin -date: 2024-01-04 +date: 2024-01-05 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 4e4bcfdef739e..172a66d34cd48 100644 --- a/api_docs/kbn_some_dev_log.mdx +++ b/api_docs/kbn_some_dev_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-some-dev-log title: "@kbn/some-dev-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/some-dev-log plugin -date: 2024-01-04 +date: 2024-01-05 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 e41f4e72b5f45..903d805980252 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/std plugin -date: 2024-01-04 +date: 2024-01-05 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 a59d24d575dd9..5a819a2483e7e 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/stdio-dev-helpers plugin -date: 2024-01-04 +date: 2024-01-05 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 463a6ccd8e6b4..ddf60813b3e6f 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/storybook plugin -date: 2024-01-04 +date: 2024-01-05 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 d017bcc4387d9..d357765de093e 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/telemetry-tools plugin -date: 2024-01-04 +date: 2024-01-05 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 dbc578273baf9..deef6f2d8bfa2 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test plugin -date: 2024-01-04 +date: 2024-01-05 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 90ad352d24301..ee0a17dd56e4b 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-jest-helpers plugin -date: 2024-01-04 +date: 2024-01-05 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 d2a83bfeb5823..8d65942208d82 100644 --- a/api_docs/kbn_test_subj_selector.mdx +++ b/api_docs/kbn_test_subj_selector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-subj-selector title: "@kbn/test-subj-selector" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-subj-selector plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-subj-selector'] --- import kbnTestSubjSelectorObj from './kbn_test_subj_selector.devdocs.json'; diff --git a/api_docs/kbn_text_based_editor.mdx b/api_docs/kbn_text_based_editor.mdx index 6fbbedbb4060e..1a147019c623f 100644 --- a/api_docs/kbn_text_based_editor.mdx +++ b/api_docs/kbn_text_based_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-text-based-editor title: "@kbn/text-based-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/text-based-editor plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/text-based-editor'] --- import kbnTextBasedEditorObj from './kbn_text_based_editor.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index 8394bd0a1bedd..0bcb9d298d2ad 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/tooling-log plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_triggers_actions_ui_types.mdx b/api_docs/kbn_triggers_actions_ui_types.mdx index 588370be25ebd..8c143f9b47d4c 100644 --- a/api_docs/kbn_triggers_actions_ui_types.mdx +++ b/api_docs/kbn_triggers_actions_ui_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-triggers-actions-ui-types title: "@kbn/triggers-actions-ui-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/triggers-actions-ui-types plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/triggers-actions-ui-types'] --- import kbnTriggersActionsUiTypesObj from './kbn_triggers_actions_ui_types.devdocs.json'; diff --git a/api_docs/kbn_ts_projects.mdx b/api_docs/kbn_ts_projects.mdx index a6f14944025e9..0bcc134f3bd72 100644 --- a/api_docs/kbn_ts_projects.mdx +++ b/api_docs/kbn_ts_projects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ts-projects title: "@kbn/ts-projects" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ts-projects plugin -date: 2024-01-04 +date: 2024-01-05 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 a98d6266b66b0..08cde87cb3cf6 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/typed-react-router-config plugin -date: 2024-01-04 +date: 2024-01-05 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 46ba6f2227f30..153d573a373e6 100644 --- a/api_docs/kbn_ui_actions_browser.mdx +++ b/api_docs/kbn_ui_actions_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-actions-browser title: "@kbn/ui-actions-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-actions-browser plugin -date: 2024-01-04 +date: 2024-01-05 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 01f1a1b95e1f8..fb710c473e0b3 100644 --- a/api_docs/kbn_ui_shared_deps_src.mdx +++ b/api_docs/kbn_ui_shared_deps_src.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-shared-deps-src title: "@kbn/ui-shared-deps-src" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-shared-deps-src plugin -date: 2024-01-04 +date: 2024-01-05 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 2054df010326b..7454b53b0e2f8 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-theme plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_unified_data_table.mdx b/api_docs/kbn_unified_data_table.mdx index 32098ef443509..2380b7372f2f5 100644 --- a/api_docs/kbn_unified_data_table.mdx +++ b/api_docs/kbn_unified_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-data-table title: "@kbn/unified-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-data-table plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-data-table'] --- import kbnUnifiedDataTableObj from './kbn_unified_data_table.devdocs.json'; diff --git a/api_docs/kbn_unified_doc_viewer.mdx b/api_docs/kbn_unified_doc_viewer.mdx index 99b430eb56fc9..79db7c5bfe3d9 100644 --- a/api_docs/kbn_unified_doc_viewer.mdx +++ b/api_docs/kbn_unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-doc-viewer title: "@kbn/unified-doc-viewer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-doc-viewer plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-doc-viewer'] --- import kbnUnifiedDocViewerObj from './kbn_unified_doc_viewer.devdocs.json'; diff --git a/api_docs/kbn_unified_field_list.mdx b/api_docs/kbn_unified_field_list.mdx index 52be5cce13839..000295820d1cb 100644 --- a/api_docs/kbn_unified_field_list.mdx +++ b/api_docs/kbn_unified_field_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-field-list title: "@kbn/unified-field-list" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-field-list plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-field-list'] --- import kbnUnifiedFieldListObj from './kbn_unified_field_list.devdocs.json'; diff --git a/api_docs/kbn_unsaved_changes_badge.mdx b/api_docs/kbn_unsaved_changes_badge.mdx index aae4e0e6b7214..455d75bd1f3da 100644 --- a/api_docs/kbn_unsaved_changes_badge.mdx +++ b/api_docs/kbn_unsaved_changes_badge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-badge title: "@kbn/unsaved-changes-badge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-badge plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-badge'] --- import kbnUnsavedChangesBadgeObj from './kbn_unsaved_changes_badge.devdocs.json'; diff --git a/api_docs/kbn_url_state.mdx b/api_docs/kbn_url_state.mdx index 52085bb35f2b4..530559e8179f5 100644 --- a/api_docs/kbn_url_state.mdx +++ b/api_docs/kbn_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-url-state title: "@kbn/url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/url-state plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/url-state'] --- import kbnUrlStateObj from './kbn_url_state.devdocs.json'; diff --git a/api_docs/kbn_use_tracked_promise.mdx b/api_docs/kbn_use_tracked_promise.mdx index 20ffe3d59787b..12971d1114d22 100644 --- a/api_docs/kbn_use_tracked_promise.mdx +++ b/api_docs/kbn_use_tracked_promise.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-use-tracked-promise title: "@kbn/use-tracked-promise" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/use-tracked-promise plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/use-tracked-promise'] --- import kbnUseTrackedPromiseObj from './kbn_use_tracked_promise.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index 10edf6016074c..dc8b88022e02a 100644 --- a/api_docs/kbn_user_profile_components.mdx +++ b/api_docs/kbn_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-user-profile-components title: "@kbn/user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/user-profile-components plugin -date: 2024-01-04 +date: 2024-01-05 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 7d3fc106dac29..202d72ad321f8 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types plugin -date: 2024-01-04 +date: 2024-01-05 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 c276f12da1e50..fad43a7ed0bdf 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types-jest plugin -date: 2024-01-04 +date: 2024-01-05 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 f069f54e5d8c3..9835772148f74 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_visualization_ui_components.mdx b/api_docs/kbn_visualization_ui_components.mdx index f5580d57a021d..844311235ca6d 100644 --- a/api_docs/kbn_visualization_ui_components.mdx +++ b/api_docs/kbn_visualization_ui_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-ui-components title: "@kbn/visualization-ui-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-ui-components plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-ui-components'] --- import kbnVisualizationUiComponentsObj from './kbn_visualization_ui_components.devdocs.json'; diff --git a/api_docs/kbn_visualization_utils.mdx b/api_docs/kbn_visualization_utils.mdx index 7f270fa1d36f3..daba78a1274ff 100644 --- a/api_docs/kbn_visualization_utils.mdx +++ b/api_docs/kbn_visualization_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-utils title: "@kbn/visualization-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-utils'] --- import kbnVisualizationUtilsObj from './kbn_visualization_utils.devdocs.json'; diff --git a/api_docs/kbn_xstate_utils.mdx b/api_docs/kbn_xstate_utils.mdx index ef70cc8f32ac4..ad4d3d9ec23ac 100644 --- a/api_docs/kbn_xstate_utils.mdx +++ b/api_docs/kbn_xstate_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-xstate-utils title: "@kbn/xstate-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/xstate-utils plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/xstate-utils'] --- import kbnXstateUtilsObj from './kbn_xstate_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index 0c633dc5c27d5..a46de2706bd40 100644 --- a/api_docs/kbn_yarn_lock_validator.mdx +++ b/api_docs/kbn_yarn_lock_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-yarn-lock-validator title: "@kbn/yarn-lock-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/yarn-lock-validator plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kbn_zod_helpers.mdx b/api_docs/kbn_zod_helpers.mdx index a418ec701d6cc..80db9667d58e5 100644 --- a/api_docs/kbn_zod_helpers.mdx +++ b/api_docs/kbn_zod_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-zod-helpers title: "@kbn/zod-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/zod-helpers plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/zod-helpers'] --- import kbnZodHelpersObj from './kbn_zod_helpers.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index f856e3a8ce372..ae784410c387a 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaOverview plugin -date: 2024-01-04 +date: 2024-01-05 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 b24f96cb3444e..a2a3d5c5ce4bb 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaReact plugin -date: 2024-01-04 +date: 2024-01-05 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 b5c7372638bcb..5ab86f6c3e6b7 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaUtils plugin -date: 2024-01-04 +date: 2024-01-05 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 a5ffb3a455b9c..91f61d77ce8da 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the kubernetesSecurity plugin -date: 2024-01-04 +date: 2024-01-05 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 162d4ed72ae98..a85196d522907 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github description: API docs for the lens plugin -date: 2024-01-04 +date: 2024-01-05 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 ea890b5957f21..d4a4818992a98 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseApiGuard plugin -date: 2024-01-04 +date: 2024-01-05 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 e3b420f9e5b17..43deddf578652 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseManagement plugin -date: 2024-01-04 +date: 2024-01-05 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 14e73c2998c72..435dff6429fe9 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github description: API docs for the licensing plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/links.mdx b/api_docs/links.mdx index cf0d1eed7664f..8961e4efc4e72 100644 --- a/api_docs/links.mdx +++ b/api_docs/links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/links title: "links" image: https://source.unsplash.com/400x175/?github description: API docs for the links plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'links'] --- import linksObj from './links.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 010957d4e13d3..e528494c28b51 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github description: API docs for the lists plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/log_explorer.mdx b/api_docs/log_explorer.mdx index 7cfcac8ae5cf6..61e28f7dd904c 100644 --- a/api_docs/log_explorer.mdx +++ b/api_docs/log_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logExplorer title: "logExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the logExplorer plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logExplorer'] --- import logExplorerObj from './log_explorer.devdocs.json'; diff --git a/api_docs/logs_shared.mdx b/api_docs/logs_shared.mdx index 0353663c316d2..5df148d5030a2 100644 --- a/api_docs/logs_shared.mdx +++ b/api_docs/logs_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsShared title: "logsShared" image: https://source.unsplash.com/400x175/?github description: API docs for the logsShared plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsShared'] --- import logsSharedObj from './logs_shared.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index eea3cf75d8548..97c2448a4a607 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github description: API docs for the management plugin -date: 2024-01-04 +date: 2024-01-05 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 816acd8202392..8249fbd219284 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github description: API docs for the maps plugin -date: 2024-01-04 +date: 2024-01-05 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 e7e002205a35a..2cb6c52f80293 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github description: API docs for the mapsEms plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/metrics_data_access.mdx b/api_docs/metrics_data_access.mdx index 9fd89853595bd..f47cdcc792385 100644 --- a/api_docs/metrics_data_access.mdx +++ b/api_docs/metrics_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/metricsDataAccess title: "metricsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the metricsDataAccess plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'metricsDataAccess'] --- import metricsDataAccessObj from './metrics_data_access.devdocs.json'; diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 682e2bdebbdff..7147bfdacb014 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github description: API docs for the ml plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/mock_idp_plugin.mdx b/api_docs/mock_idp_plugin.mdx index d4b39b356cba6..fdadf8f97a194 100644 --- a/api_docs/mock_idp_plugin.mdx +++ b/api_docs/mock_idp_plugin.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mockIdpPlugin title: "mockIdpPlugin" image: https://source.unsplash.com/400x175/?github description: API docs for the mockIdpPlugin plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mockIdpPlugin'] --- import mockIdpPluginObj from './mock_idp_plugin.devdocs.json'; diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index 2f971fff8ff49..de35753b2b772 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoring plugin -date: 2024-01-04 +date: 2024-01-05 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 be8ae0637856b..6755ee6a39ee0 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoringCollection plugin -date: 2024-01-04 +date: 2024-01-05 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 9356cae6383b0..46c8c85aa1280 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the navigation plugin -date: 2024-01-04 +date: 2024-01-05 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 9947a396715b1..48caf17193c0e 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github description: API docs for the newsfeed plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/no_data_page.mdx b/api_docs/no_data_page.mdx index 3031839874fc8..e45789a082436 100644 --- a/api_docs/no_data_page.mdx +++ b/api_docs/no_data_page.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/noDataPage title: "noDataPage" image: https://source.unsplash.com/400x175/?github description: API docs for the noDataPage plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'noDataPage'] --- import noDataPageObj from './no_data_page.devdocs.json'; diff --git a/api_docs/notifications.mdx b/api_docs/notifications.mdx index 68875d62f9d62..f5e5b2f68ea4e 100644 --- a/api_docs/notifications.mdx +++ b/api_docs/notifications.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/notifications title: "notifications" image: https://source.unsplash.com/400x175/?github description: API docs for the notifications plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'notifications'] --- import notificationsObj from './notifications.devdocs.json'; diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index bbb951a816d2a..1aabd1bace5e3 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observability title: "observability" image: https://source.unsplash.com/400x175/?github description: API docs for the observability plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index 3f95923dd0f9c..4ebd383be1990 100644 --- a/api_docs/observability_a_i_assistant.mdx +++ b/api_docs/observability_a_i_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAIAssistant title: "observabilityAIAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAIAssistant plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistant'] --- import observabilityAIAssistantObj from './observability_a_i_assistant.devdocs.json'; diff --git a/api_docs/observability_log_explorer.mdx b/api_docs/observability_log_explorer.mdx index 302ac71a55f4f..f6df8e3688821 100644 --- a/api_docs/observability_log_explorer.mdx +++ b/api_docs/observability_log_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityLogExplorer title: "observabilityLogExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityLogExplorer plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityLogExplorer'] --- import observabilityLogExplorerObj from './observability_log_explorer.devdocs.json'; diff --git a/api_docs/observability_onboarding.mdx b/api_docs/observability_onboarding.mdx index da8442b82ed09..41404c514c318 100644 --- a/api_docs/observability_onboarding.mdx +++ b/api_docs/observability_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityOnboarding title: "observabilityOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityOnboarding plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityOnboarding'] --- import observabilityOnboardingObj from './observability_onboarding.devdocs.json'; diff --git a/api_docs/observability_shared.mdx b/api_docs/observability_shared.mdx index 74848aaa6f3f1..e625482424d63 100644 --- a/api_docs/observability_shared.mdx +++ b/api_docs/observability_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityShared title: "observabilityShared" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityShared plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityShared'] --- import observabilitySharedObj from './observability_shared.devdocs.json'; diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index be0ab0aceff46..0506487c4bb88 100644 --- a/api_docs/osquery.mdx +++ b/api_docs/osquery.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/osquery title: "osquery" image: https://source.unsplash.com/400x175/?github description: API docs for the osquery plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/painless_lab.mdx b/api_docs/painless_lab.mdx index be7778b29462f..6514a7ff90bca 100644 --- a/api_docs/painless_lab.mdx +++ b/api_docs/painless_lab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/painlessLab title: "painlessLab" image: https://source.unsplash.com/400x175/?github description: API docs for the painlessLab plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'painlessLab'] --- import painlessLabObj from './painless_lab.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index c93080b72b3ad..c3f83b74fae47 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -7,7 +7,7 @@ id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory description: Directory of public APIs available through plugins or packages. -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -21,7 +21,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 78161 | 234 | 66877 | 1696 | +| 78586 | 237 | 67267 | 1696 | ## Plugin Directory @@ -70,7 +70,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 37 | 0 | 35 | 2 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | APIs used to assess the quality of data in Elasticsearch indexes | 2 | 0 | 0 | 0 | | | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | Server APIs for the Elastic AI Assistant | 36 | 0 | 28 | 0 | -| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds embeddables service to Kibana | 547 | 1 | 446 | 8 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds embeddables service to Kibana | 541 | 1 | 440 | 7 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Extends embeddable plugin with more functionality | 14 | 0 | 14 | 0 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides encryption and decryption utilities for saved objects containing sensitive information. | 53 | 0 | 46 | 1 | | | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | Adds dashboards for discovering and managing Enterprise Search products. | 5 | 0 | 5 | 0 | @@ -469,7 +469,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 37 | 0 | 29 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 0 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 29 | 0 | 29 | 1 | -| | [@elastic/appex-qa](https://github.com/orgs/elastic/teams/appex-qa) | - | 4 | 0 | 4 | 0 | +| | [@elastic/appex-qa](https://github.com/orgs/elastic/teams/appex-qa) | - | 435 | 3 | 400 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 1 | 0 | 0 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 1 | 0 | 1 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 10 | 0 | 10 | 1 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index 6e6c5741a6ec7..74e6e10decd07 100644 --- a/api_docs/presentation_util.mdx +++ b/api_docs/presentation_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationUtil title: "presentationUtil" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationUtil plugin -date: 2024-01-04 +date: 2024-01-05 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 399dd64183353..29f635109fcc8 100644 --- a/api_docs/profiling.mdx +++ b/api_docs/profiling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profiling title: "profiling" image: https://source.unsplash.com/400x175/?github description: API docs for the profiling plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; diff --git a/api_docs/profiling_data_access.mdx b/api_docs/profiling_data_access.mdx index f6311d7c54487..d4b71e053ed65 100644 --- a/api_docs/profiling_data_access.mdx +++ b/api_docs/profiling_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profilingDataAccess title: "profilingDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the profilingDataAccess plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profilingDataAccess'] --- import profilingDataAccessObj from './profiling_data_access.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index 78c2e5aa4aa53..44d743b543ed2 100644 --- a/api_docs/remote_clusters.mdx +++ b/api_docs/remote_clusters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/remoteClusters title: "remoteClusters" image: https://source.unsplash.com/400x175/?github description: API docs for the remoteClusters plugin -date: 2024-01-04 +date: 2024-01-05 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 40ad623e1af45..3329e5263415d 100644 --- a/api_docs/reporting.mdx +++ b/api_docs/reporting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/reporting title: "reporting" image: https://source.unsplash.com/400x175/?github description: API docs for the reporting plugin -date: 2024-01-04 +date: 2024-01-05 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 250319a684a61..06ebfce041714 100644 --- a/api_docs/rollup.mdx +++ b/api_docs/rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/rollup title: "rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the rollup plugin -date: 2024-01-04 +date: 2024-01-05 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 c951acaa232dd..62e7671dd9895 100644 --- a/api_docs/rule_registry.mdx +++ b/api_docs/rule_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ruleRegistry title: "ruleRegistry" image: https://source.unsplash.com/400x175/?github description: API docs for the ruleRegistry plugin -date: 2024-01-04 +date: 2024-01-05 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 9db85c536b5c1..0fb857e630089 100644 --- a/api_docs/runtime_fields.mdx +++ b/api_docs/runtime_fields.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/runtimeFields title: "runtimeFields" image: https://source.unsplash.com/400x175/?github description: API docs for the runtimeFields plugin -date: 2024-01-04 +date: 2024-01-05 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 603b1a75edb62..0892b8561c119 100644 --- a/api_docs/saved_objects.mdx +++ b/api_docs/saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjects title: "savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjects plugin -date: 2024-01-04 +date: 2024-01-05 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 9597a8287cc37..246e8be6725e1 100644 --- a/api_docs/saved_objects_finder.mdx +++ b/api_docs/saved_objects_finder.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsFinder title: "savedObjectsFinder" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsFinder plugin -date: 2024-01-04 +date: 2024-01-05 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 a437d3b666cea..8a92cc6216763 100644 --- a/api_docs/saved_objects_management.mdx +++ b/api_docs/saved_objects_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsManagement title: "savedObjectsManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsManagement plugin -date: 2024-01-04 +date: 2024-01-05 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 e72d964311e90..cbaba9681304e 100644 --- a/api_docs/saved_objects_tagging.mdx +++ b/api_docs/saved_objects_tagging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTagging title: "savedObjectsTagging" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTagging plugin -date: 2024-01-04 +date: 2024-01-05 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 903def8f53d00..8089744a3da73 100644 --- a/api_docs/saved_objects_tagging_oss.mdx +++ b/api_docs/saved_objects_tagging_oss.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTaggingOss title: "savedObjectsTaggingOss" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTaggingOss plugin -date: 2024-01-04 +date: 2024-01-05 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 7ce63486b6cf5..122cd18cbcdc3 100644 --- a/api_docs/saved_search.mdx +++ b/api_docs/saved_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedSearch title: "savedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the savedSearch plugin -date: 2024-01-04 +date: 2024-01-05 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 87cc479ecea93..68c9adfa10b51 100644 --- a/api_docs/screenshot_mode.mdx +++ b/api_docs/screenshot_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotMode title: "screenshotMode" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotMode plugin -date: 2024-01-04 +date: 2024-01-05 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 fb382915fbd09..10361f87a534b 100644 --- a/api_docs/screenshotting.mdx +++ b/api_docs/screenshotting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotting title: "screenshotting" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotting plugin -date: 2024-01-04 +date: 2024-01-05 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 8fd74810bb99c..9bf5b994cc406 100644 --- a/api_docs/security.mdx +++ b/api_docs/security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/security title: "security" image: https://source.unsplash.com/400x175/?github description: API docs for the security plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; diff --git a/api_docs/security_solution.devdocs.json b/api_docs/security_solution.devdocs.json index c50901f256cad..816001e8e21b1 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -114,7 +114,7 @@ "label": "experimentalFeatures", "description": [], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" ], "path": "x-pack/plugins/security_solution/public/plugin.tsx", "deprecated": false, @@ -568,7 +568,7 @@ "\nExperimental flag needed to enable the link" ], "signature": [ - "\"tGridEnabled\" | \"tGridEventRenderedViewEnabled\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"chartEmbeddablesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"alertsPreviewChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"insightsRelatedAlertsByProcessAncestry\" | \"extendedRuleExecutionLoggingEnabled\" | \"assistantStreamingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutInCreateRuleEnabled\" | \"alertsPageFiltersEnabled\" | \"assistantModelEvaluation\" | \"newUserDetailsFlyout\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"entityAnalyticsAssetCriticalityEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"jsonPrebuiltRulesDiffingEnabled\" | \"timelineEsqlTabDisabled\" | undefined" + "\"tGridEnabled\" | \"tGridEventRenderedViewEnabled\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"chartEmbeddablesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"alertsPreviewChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"insightsRelatedAlertsByProcessAncestry\" | \"extendedRuleExecutionLoggingEnabled\" | \"assistantStreamingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutInCreateRuleEnabled\" | \"alertsPageFiltersEnabled\" | \"assistantModelEvaluation\" | \"newUserDetailsFlyout\" | \"newHostDetailsFlyout\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"entityAnalyticsAssetCriticalityEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"jsonPrebuiltRulesDiffingEnabled\" | \"timelineEsqlTabDisabled\" | undefined" ], "path": "x-pack/plugins/security_solution/public/common/links/types.ts", "deprecated": false, @@ -648,7 +648,7 @@ "\nExperimental flag needed to disable the link. Opposite of experimentalKey" ], "signature": [ - "\"tGridEnabled\" | \"tGridEventRenderedViewEnabled\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"chartEmbeddablesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"alertsPreviewChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"insightsRelatedAlertsByProcessAncestry\" | \"extendedRuleExecutionLoggingEnabled\" | \"assistantStreamingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutInCreateRuleEnabled\" | \"alertsPageFiltersEnabled\" | \"assistantModelEvaluation\" | \"newUserDetailsFlyout\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"entityAnalyticsAssetCriticalityEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"jsonPrebuiltRulesDiffingEnabled\" | \"timelineEsqlTabDisabled\" | undefined" + "\"tGridEnabled\" | \"tGridEventRenderedViewEnabled\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"chartEmbeddablesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"alertsPreviewChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"insightsRelatedAlertsByProcessAncestry\" | \"extendedRuleExecutionLoggingEnabled\" | \"assistantStreamingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutInCreateRuleEnabled\" | \"alertsPageFiltersEnabled\" | \"assistantModelEvaluation\" | \"newUserDetailsFlyout\" | \"newHostDetailsFlyout\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"entityAnalyticsAssetCriticalityEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"jsonPrebuiltRulesDiffingEnabled\" | \"timelineEsqlTabDisabled\" | undefined" ], "path": "x-pack/plugins/security_solution/public/common/links/types.ts", "deprecated": false, @@ -1913,7 +1913,7 @@ "label": "experimentalFeatures", "description": [], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" ], "path": "x-pack/plugins/security_solution/public/types.ts", "deprecated": false, @@ -3018,7 +3018,7 @@ "\nThe security solution generic experimental features" ], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" ], "path": "x-pack/plugins/security_solution/server/plugin_contract.ts", "deprecated": false, @@ -3194,7 +3194,7 @@ "label": "ExperimentalFeatures", "description": [], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, @@ -3243,7 +3243,7 @@ "\nA list of allowed values that can be used in `xpack.securitySolution.enableExperimental`.\nThis object is then used to validate and parse the value entered." ], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index 8eef95d5129ce..ba6c70b164553 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolution title: "securitySolution" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolution plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/security_solution_ess.mdx b/api_docs/security_solution_ess.mdx index ffa55031142c3..25f68ee7e5510 100644 --- a/api_docs/security_solution_ess.mdx +++ b/api_docs/security_solution_ess.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionEss title: "securitySolutionEss" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionEss plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionEss'] --- import securitySolutionEssObj from './security_solution_ess.devdocs.json'; diff --git a/api_docs/security_solution_serverless.mdx b/api_docs/security_solution_serverless.mdx index 1424cf9913554..c3e1d15be89e9 100644 --- a/api_docs/security_solution_serverless.mdx +++ b/api_docs/security_solution_serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionServerless title: "securitySolutionServerless" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionServerless plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionServerless'] --- import securitySolutionServerlessObj from './security_solution_serverless.devdocs.json'; diff --git a/api_docs/serverless.mdx b/api_docs/serverless.mdx index 2e7a6aadd704b..077333a053dfb 100644 --- a/api_docs/serverless.mdx +++ b/api_docs/serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverless title: "serverless" image: https://source.unsplash.com/400x175/?github description: API docs for the serverless plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverless'] --- import serverlessObj from './serverless.devdocs.json'; diff --git a/api_docs/serverless_observability.mdx b/api_docs/serverless_observability.mdx index 1bf96e28966e0..534e533edab52 100644 --- a/api_docs/serverless_observability.mdx +++ b/api_docs/serverless_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessObservability title: "serverlessObservability" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessObservability plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessObservability'] --- import serverlessObservabilityObj from './serverless_observability.devdocs.json'; diff --git a/api_docs/serverless_search.mdx b/api_docs/serverless_search.mdx index fc4b453d0c79d..102604d95ab79 100644 --- a/api_docs/serverless_search.mdx +++ b/api_docs/serverless_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessSearch title: "serverlessSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessSearch plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessSearch'] --- import serverlessSearchObj from './serverless_search.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index 2f8c9f437ccb8..763ca419fed88 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/sessionView title: "sessionView" image: https://source.unsplash.com/400x175/?github description: API docs for the sessionView plugin -date: 2024-01-04 +date: 2024-01-05 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 a0d28e5a26b04..339d6c508087c 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/share title: "share" image: https://source.unsplash.com/400x175/?github description: API docs for the share plugin -date: 2024-01-04 +date: 2024-01-05 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 dba4bc4e7e8b5..21f5f0258bc20 100644 --- a/api_docs/snapshot_restore.mdx +++ b/api_docs/snapshot_restore.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/snapshotRestore title: "snapshotRestore" image: https://source.unsplash.com/400x175/?github description: API docs for the snapshotRestore plugin -date: 2024-01-04 +date: 2024-01-05 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 f638dca83f957..4c7128a9930d5 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/spaces title: "spaces" image: https://source.unsplash.com/400x175/?github description: API docs for the spaces plugin -date: 2024-01-04 +date: 2024-01-05 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 88a3c55dc67b7..27324a3195cd1 100644 --- a/api_docs/stack_alerts.mdx +++ b/api_docs/stack_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackAlerts title: "stackAlerts" image: https://source.unsplash.com/400x175/?github description: API docs for the stackAlerts plugin -date: 2024-01-04 +date: 2024-01-05 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 86f2c02b51559..fad3a15191dcb 100644 --- a/api_docs/stack_connectors.mdx +++ b/api_docs/stack_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackConnectors title: "stackConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the stackConnectors plugin -date: 2024-01-04 +date: 2024-01-05 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 56924fd413208..b73de4d4a8f85 100644 --- a/api_docs/task_manager.mdx +++ b/api_docs/task_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/taskManager title: "taskManager" image: https://source.unsplash.com/400x175/?github description: API docs for the taskManager plugin -date: 2024-01-04 +date: 2024-01-05 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 4fad05863370d..adbb8316668a9 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetry title: "telemetry" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetry plugin -date: 2024-01-04 +date: 2024-01-05 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 a690d153a5453..dac5b90d56c34 100644 --- a/api_docs/telemetry_collection_manager.mdx +++ b/api_docs/telemetry_collection_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionManager title: "telemetryCollectionManager" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionManager plugin -date: 2024-01-04 +date: 2024-01-05 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 1a6dadc567f66..d4800130c11ed 100644 --- a/api_docs/telemetry_collection_xpack.mdx +++ b/api_docs/telemetry_collection_xpack.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionXpack title: "telemetryCollectionXpack" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionXpack plugin -date: 2024-01-04 +date: 2024-01-05 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 d280cb1dbe2d7..b802885ce63c8 100644 --- a/api_docs/telemetry_management_section.mdx +++ b/api_docs/telemetry_management_section.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryManagementSection title: "telemetryManagementSection" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryManagementSection plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/text_based_languages.mdx b/api_docs/text_based_languages.mdx index cc12aff43841a..90f4c737ef5d5 100644 --- a/api_docs/text_based_languages.mdx +++ b/api_docs/text_based_languages.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/textBasedLanguages title: "textBasedLanguages" image: https://source.unsplash.com/400x175/?github description: API docs for the textBasedLanguages plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'textBasedLanguages'] --- import textBasedLanguagesObj from './text_based_languages.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index b2400c6a56059..e65d055c5015b 100644 --- a/api_docs/threat_intelligence.mdx +++ b/api_docs/threat_intelligence.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/threatIntelligence title: "threatIntelligence" image: https://source.unsplash.com/400x175/?github description: API docs for the threatIntelligence plugin -date: 2024-01-04 +date: 2024-01-05 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 089062e668317..623a249277ff8 100644 --- a/api_docs/timelines.mdx +++ b/api_docs/timelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/timelines title: "timelines" image: https://source.unsplash.com/400x175/?github description: API docs for the timelines plugin -date: 2024-01-04 +date: 2024-01-05 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 e1380a11e5fb2..c8d87b3d53b18 100644 --- a/api_docs/transform.mdx +++ b/api_docs/transform.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/transform title: "transform" image: https://source.unsplash.com/400x175/?github description: API docs for the transform plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index 34d9b1ae953ba..a88344d51d8fe 100644 --- a/api_docs/triggers_actions_ui.mdx +++ b/api_docs/triggers_actions_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/triggersActionsUi title: "triggersActionsUi" image: https://source.unsplash.com/400x175/?github description: API docs for the triggersActionsUi plugin -date: 2024-01-04 +date: 2024-01-05 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 14ec4d033c757..0588c01b591f6 100644 --- a/api_docs/ui_actions.mdx +++ b/api_docs/ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActions title: "uiActions" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActions plugin -date: 2024-01-04 +date: 2024-01-05 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 06ed1525dd171..be083bd8db8b1 100644 --- a/api_docs/ui_actions_enhanced.mdx +++ b/api_docs/ui_actions_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActionsEnhanced title: "uiActionsEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActionsEnhanced plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_doc_viewer.mdx b/api_docs/unified_doc_viewer.mdx index 9a912ac1027c1..0bd5ea3e32041 100644 --- a/api_docs/unified_doc_viewer.mdx +++ b/api_docs/unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedDocViewer title: "unifiedDocViewer" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedDocViewer plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedDocViewer'] --- import unifiedDocViewerObj from './unified_doc_viewer.devdocs.json'; diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index 9bec81e68ad55..bcbef43c6e33b 100644 --- a/api_docs/unified_histogram.mdx +++ b/api_docs/unified_histogram.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedHistogram title: "unifiedHistogram" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedHistogram plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedHistogram'] --- import unifiedHistogramObj from './unified_histogram.devdocs.json'; diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index b98e1e61aa279..3b4027f728d85 100644 --- a/api_docs/unified_search.mdx +++ b/api_docs/unified_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch title: "unifiedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] --- import unifiedSearchObj from './unified_search.devdocs.json'; diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index 1d7c6f9317dfd..5d9fe8a04f0c1 100644 --- a/api_docs/unified_search_autocomplete.mdx +++ b/api_docs/unified_search_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch-autocomplete title: "unifiedSearch.autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch.autocomplete plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; diff --git a/api_docs/uptime.mdx b/api_docs/uptime.mdx index 92ee3d44518da..779a7b84fe526 100644 --- a/api_docs/uptime.mdx +++ b/api_docs/uptime.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uptime title: "uptime" image: https://source.unsplash.com/400x175/?github description: API docs for the uptime plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uptime'] --- import uptimeObj from './uptime.devdocs.json'; diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index d7d4d5e1139d6..5a91922a20ba3 100644 --- a/api_docs/url_forwarding.mdx +++ b/api_docs/url_forwarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/urlForwarding title: "urlForwarding" image: https://source.unsplash.com/400x175/?github description: API docs for the urlForwarding plugin -date: 2024-01-04 +date: 2024-01-05 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 5672f86c23a08..1938ebf53a753 100644 --- a/api_docs/usage_collection.mdx +++ b/api_docs/usage_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/usageCollection title: "usageCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the usageCollection plugin -date: 2024-01-04 +date: 2024-01-05 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 024cb71786684..669c55c297b0e 100644 --- a/api_docs/ux.mdx +++ b/api_docs/ux.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ux title: "ux" image: https://source.unsplash.com/400x175/?github description: API docs for the ux plugin -date: 2024-01-04 +date: 2024-01-05 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 18110a2986cd7..65878ec3d271e 100644 --- a/api_docs/vis_default_editor.mdx +++ b/api_docs/vis_default_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visDefaultEditor title: "visDefaultEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the visDefaultEditor plugin -date: 2024-01-04 +date: 2024-01-05 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 6d093cb710b76..c89a81f472595 100644 --- a/api_docs/vis_type_gauge.mdx +++ b/api_docs/vis_type_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeGauge title: "visTypeGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeGauge plugin -date: 2024-01-04 +date: 2024-01-05 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 1320fe72ef085..5390a71f9dd26 100644 --- a/api_docs/vis_type_heatmap.mdx +++ b/api_docs/vis_type_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeHeatmap title: "visTypeHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeHeatmap plugin -date: 2024-01-04 +date: 2024-01-05 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 19d7fa2ba0e22..4f11ecdc9acea 100644 --- a/api_docs/vis_type_pie.mdx +++ b/api_docs/vis_type_pie.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypePie title: "visTypePie" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypePie plugin -date: 2024-01-04 +date: 2024-01-05 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 358e0aa109bfd..888f28ef64f7e 100644 --- a/api_docs/vis_type_table.mdx +++ b/api_docs/vis_type_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTable title: "visTypeTable" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTable plugin -date: 2024-01-04 +date: 2024-01-05 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 8e70657f3210d..dcd8f9dc2e15a 100644 --- a/api_docs/vis_type_timelion.mdx +++ b/api_docs/vis_type_timelion.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimelion title: "visTypeTimelion" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimelion plugin -date: 2024-01-04 +date: 2024-01-05 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 8df27109a1300..9df8977c8abe0 100644 --- a/api_docs/vis_type_timeseries.mdx +++ b/api_docs/vis_type_timeseries.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimeseries title: "visTypeTimeseries" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimeseries plugin -date: 2024-01-04 +date: 2024-01-05 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 0c5734a0dbf20..b675520306dd3 100644 --- a/api_docs/vis_type_vega.mdx +++ b/api_docs/vis_type_vega.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVega title: "visTypeVega" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVega plugin -date: 2024-01-04 +date: 2024-01-05 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 4e0db374f9487..e75e83e13f70a 100644 --- a/api_docs/vis_type_vislib.mdx +++ b/api_docs/vis_type_vislib.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVislib title: "visTypeVislib" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVislib plugin -date: 2024-01-04 +date: 2024-01-05 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 193a6c9b0e2c7..cf476fb5dc48c 100644 --- a/api_docs/vis_type_xy.mdx +++ b/api_docs/vis_type_xy.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeXy title: "visTypeXy" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeXy plugin -date: 2024-01-04 +date: 2024-01-05 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 7232243e38c10..22233095d28e5 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visualizations title: "visualizations" image: https://source.unsplash.com/400x175/?github description: API docs for the visualizations plugin -date: 2024-01-04 +date: 2024-01-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; From 35514f7fec7119f3d1dc60ab804776c867d6ec29 Mon Sep 17 00:00:00 2001 From: Julia Bardi <90178898+juliaElastic@users.noreply.github.com> Date: Fri, 5 Jan 2024 09:19:51 +0100 Subject: [PATCH 034/100] [Fleet] fix kafka ssl key secret update (#174261) ## Summary Closes https://github.com/elastic/kibana/issues/174227 Fix wrong field used for kafka ssl key secret input which broke ssl key on kafka output update. To verify: - create a kafka output with Authentication: SSL, fill out cert and key - verify that the value of the key is stored as secret in `.fleet-secrets` - update kafka output (e.g. change name) - verify that the ssl key is unchanged image --- .../settings/components/edit_output_flyout/use_output_form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.tsx index a1d0fb484b44f..81753d9c56c38 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.tsx @@ -399,7 +399,7 @@ export function useOutputForm(onSucess: () => void, output?: Output) { ); const kafkaSslKeySecretInput = useSecretInput( - kafkaOutput?.ssl?.certificate, + kafkaOutput?.secrets?.ssl?.key, kafkaAuthMethodInput.value === kafkaAuthType.Ssl ? validateSSLKeySecret : undefined, isSSLEditable ); From 702b207d2d93019e9efa3f00fdd48c9328c2f893 Mon Sep 17 00:00:00 2001 From: Maryam Saeidi Date: Fri, 5 Jan 2024 11:30:10 +0100 Subject: [PATCH 035/100] [Custom threshold] Add log rate analysis to the alert details page for one document count aggregation (#174031) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #171163 ## Summary This PR adds log rate analysis to the alert details page for one document count aggregation if the user has a license above platinum. This is a similar implementation in the log threshold alert details page. ![image](https://github.com/elastic/kibana/assets/12370520/29cd29bf-ead5-4574-8121-739d3ed11fe7) ## 🧪 How to test? - Create a Custom threshold rule with only one document count aggregation - Optional filter, document count aggregation filter, and group by information will be applied to the query of this component. - Go to the alert details page, you should see the log rate analysis on this page --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../common/custom_threshold_rule/types.ts | 5 + .../utils/get_interval_in_seconds.test.ts | 28 +++ .../common/utils/get_interval_in_seconds.ts | 32 +++ x-pack/plugins/observability/kibana.jsonc | 1 + .../alert_search_bar/alert_search_bar.tsx | 22 +- .../alert_details_app_section.test.tsx.snap | 0 .../alert_details_app_section.test.tsx | 8 +- .../alert_details_app_section.tsx | 28 ++- .../log_rate_analysis_query.test.ts.snap | 222 ++++++++++++++++ .../helpers/get_initial_analysis_start.ts | 58 +++++ .../helpers/log_rate_analysis_query.test.ts | 98 ++++++++ .../helpers/log_rate_analysis_query.ts | 62 +++++ .../log_rate_analysis.tsx | 238 ++++++++++++++++++ .../mocks/custom_threshold_rule.ts | 5 +- .../observability/public/hooks/use_license.ts | 4 +- .../public/pages/overview/overview.tsx | 18 +- x-pack/plugins/observability/public/plugin.ts | 3 + .../register_observability_rule_types.ts | 5 +- .../build_es_query/build_es_query.test.ts | 2 +- .../utils/build_es_query/build_es_query.ts | 14 +- .../custom_threshold/lib/evaluate_rule.ts | 3 +- .../lib/rules/custom_threshold/utils.ts | 26 -- x-pack/plugins/observability/tsconfig.json | 4 +- 23 files changed, 816 insertions(+), 70 deletions(-) create mode 100644 x-pack/plugins/observability/common/utils/get_interval_in_seconds.test.ts create mode 100644 x-pack/plugins/observability/common/utils/get_interval_in_seconds.ts rename x-pack/plugins/observability/public/components/custom_threshold/components/{ => alert_details_app_section}/__snapshots__/alert_details_app_section.test.tsx.snap (100%) rename x-pack/plugins/observability/public/components/custom_threshold/components/{ => alert_details_app_section}/alert_details_app_section.test.tsx (94%) rename x-pack/plugins/observability/public/components/custom_threshold/components/{ => alert_details_app_section}/alert_details_app_section.tsx (86%) create mode 100644 x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/__snapshots__/log_rate_analysis_query.test.ts.snap create mode 100644 x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/get_initial_analysis_start.ts create mode 100644 x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/log_rate_analysis_query.test.ts create mode 100644 x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/log_rate_analysis_query.ts create mode 100644 x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/log_rate_analysis.tsx diff --git a/x-pack/plugins/observability/common/custom_threshold_rule/types.ts b/x-pack/plugins/observability/common/custom_threshold_rule/types.ts index 7668e19dc3900..67849df1b59d7 100644 --- a/x-pack/plugins/observability/common/custom_threshold_rule/types.ts +++ b/x-pack/plugins/observability/common/custom_threshold_rule/types.ts @@ -107,6 +107,11 @@ export enum InfraFormatterType { percent = 'percent', } +// Custom threshold alert types + +// Alert fields['kibana.alert.group] type +export type GroupBy = Array<{ field: string; value: string }>; + /* * Utils * diff --git a/x-pack/plugins/observability/common/utils/get_interval_in_seconds.test.ts b/x-pack/plugins/observability/common/utils/get_interval_in_seconds.test.ts new file mode 100644 index 0000000000000..f2654a224ae86 --- /dev/null +++ b/x-pack/plugins/observability/common/utils/get_interval_in_seconds.test.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 { getIntervalInSeconds } from './get_interval_in_seconds'; + +describe('getIntervalInSeconds', () => { + const testData = [ + { interval: '5ms', result: 0.005 }, + { interval: '70s', result: 70 }, + { interval: '25m', result: 1500 }, + { interval: '10h', result: 36000 }, + { interval: '3d', result: 259200 }, + { interval: '1w', result: 604800 }, + { interval: '1y', result: 30758400 }, + ]; + + it.each(testData)('getIntervalInSeconds($interval) = $result', ({ interval, result }) => { + expect(getIntervalInSeconds(interval)).toBe(result); + }); + + it('Throws error if interval is not valid', () => { + expect(() => getIntervalInSeconds('invalid')).toThrow('Invalid interval string format.'); + }); +}); diff --git a/x-pack/plugins/observability/common/utils/get_interval_in_seconds.ts b/x-pack/plugins/observability/common/utils/get_interval_in_seconds.ts new file mode 100644 index 0000000000000..6ebdbb83bdc62 --- /dev/null +++ b/x-pack/plugins/observability/common/utils/get_interval_in_seconds.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +const intervalUnits = ['y', 'M', 'w', 'd', 'h', 'm', 's', 'ms']; +const INTERVAL_STRING_RE = new RegExp('^([0-9\\.]*)\\s*(' + intervalUnits.join('|') + ')$'); + +interface UnitsToSeconds { + [unit: string]: number; +} + +const units: UnitsToSeconds = { + ms: 0.001, + s: 1, + m: 60, + h: 3600, + d: 86400, + w: 86400 * 7, + M: 86400 * 30, + y: 86400 * 356, +}; + +export const getIntervalInSeconds = (interval: string): number => { + const matches = interval.match(INTERVAL_STRING_RE); + if (matches) { + return parseFloat(matches[1]) * units[matches[2]]; + } + throw new Error('Invalid interval string format.'); +}; diff --git a/x-pack/plugins/observability/kibana.jsonc b/x-pack/plugins/observability/kibana.jsonc index 526c283c0f0be..c7fdb22b5f792 100644 --- a/x-pack/plugins/observability/kibana.jsonc +++ b/x-pack/plugins/observability/kibana.jsonc @@ -20,6 +20,7 @@ "dataViews", "dataViewEditor", "embeddable", + "fieldFormats", "uiActions", "presentationUtil", "exploratoryView", diff --git a/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.tsx b/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.tsx index d27e32970f2fa..ff69c8e2ff2c3 100644 --- a/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.tsx +++ b/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.tsx @@ -47,15 +47,15 @@ export function ObservabilityAlertSearchBar({ (alertStatus: AlertStatus) => { try { onEsQueryChange( - buildEsQuery( - { + buildEsQuery({ + timeRange: { to: rangeTo, from: rangeFrom, }, kuery, - [...getAlertStatusQuery(alertStatus), ...defaultSearchQueries], - getEsQueryConfig(uiSettings) - ) + queries: [...getAlertStatusQuery(alertStatus), ...defaultSearchQueries], + config: getEsQueryConfig(uiSettings), + }) ); } catch (error) { toasts.addError(error, { @@ -89,15 +89,15 @@ export function ObservabilityAlertSearchBar({ ({ dateRange, query }) => { try { // First try to create es query to make sure query is valid, then save it in state - const esQuery = buildEsQuery( - { + const esQuery = buildEsQuery({ + timeRange: { to: dateRange.to, from: dateRange.from, }, - query, - [...getAlertStatusQuery(status), ...defaultSearchQueries], - getEsQueryConfig(uiSettings) - ); + kuery: query, + queries: [...getAlertStatusQuery(status), ...defaultSearchQueries], + config: getEsQueryConfig(uiSettings), + }); if (query) onKueryChange(query); timeFilterService.setTime(dateRange); onRangeFromChange(dateRange.from); diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/__snapshots__/alert_details_app_section.test.tsx.snap b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/__snapshots__/alert_details_app_section.test.tsx.snap similarity index 100% rename from x-pack/plugins/observability/public/components/custom_threshold/components/__snapshots__/alert_details_app_section.test.tsx.snap rename to x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/__snapshots__/alert_details_app_section.test.tsx.snap diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section.test.tsx b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.test.tsx similarity index 94% rename from x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section.test.tsx rename to x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.test.tsx index 8747558251da3..c623d9aa15043 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section.test.tsx +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.test.tsx @@ -15,9 +15,9 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { buildCustomThresholdAlert, buildCustomThresholdRule, -} from '../mocks/custom_threshold_rule'; +} from '../../mocks/custom_threshold_rule'; import AlertDetailsAppSection from './alert_details_app_section'; -import { ExpressionChart } from './expression_chart'; +import { ExpressionChart } from '../expression_chart'; const mockedChartStartContract = chartPluginMock.createStartContract(); @@ -33,11 +33,11 @@ jest.mock('@kbn/observability-get-padded-alert-time-range-util', () => ({ }), })); -jest.mock('./expression_chart', () => ({ +jest.mock('../expression_chart', () => ({ ExpressionChart: jest.fn(() =>
    ), })); -jest.mock('../../../utils/kibana_react', () => ({ +jest.mock('../../../../utils/kibana_react', () => ({ useKibana: () => ({ services: { ...mockCoreMock.createStart(), diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section.tsx b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.tsx similarity index 86% rename from x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section.tsx rename to x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.tsx index ce9a651a7a1e3..3c95f0d6677b6 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section.tsx +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.tsx @@ -25,15 +25,16 @@ import { Rule, RuleTypeParams } from '@kbn/alerting-plugin/common'; import { AlertAnnotation, AlertActiveTimeRangeAnnotation } from '@kbn/observability-alert-details'; import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-time-range-util'; import { DataView } from '@kbn/data-views-plugin/common'; -import { MetricsExplorerChartType } from '../../../../common/custom_threshold_rule/types'; -import { useKibana } from '../../../utils/kibana_react'; -import { metricValueFormatter } from '../../../../common/custom_threshold_rule/metric_value_formatter'; -import { AlertSummaryField, TopAlert } from '../../..'; - -import { ExpressionChart } from './expression_chart'; -import { TIME_LABELS } from './criterion_preview_chart/criterion_preview_chart'; -import { Threshold } from './custom_threshold'; -import { AlertParams, CustomThresholdRuleTypeParams } from '../types'; +import { MetricsExplorerChartType } from '../../../../../common/custom_threshold_rule/types'; +import { useLicense } from '../../../../hooks/use_license'; +import { useKibana } from '../../../../utils/kibana_react'; +import { metricValueFormatter } from '../../../../../common/custom_threshold_rule/metric_value_formatter'; +import { AlertSummaryField, TopAlert } from '../../../..'; +import { AlertParams, CustomThresholdRuleTypeParams } from '../../types'; +import { ExpressionChart } from '../expression_chart'; +import { TIME_LABELS } from '../criterion_preview_chart/criterion_preview_chart'; +import { Threshold } from '../custom_threshold'; +import { LogRateAnalysis } from './log_rate_analysis'; // TODO Use a generic props for app sections https://github.com/elastic/kibana/issues/152690 export type CustomThresholdRule = Rule; @@ -57,8 +58,11 @@ export default function AlertDetailsAppSection({ ruleLink, setAlertSummaryFields, }: AppSectionProps) { - const { uiSettings, charts, data } = useKibana().services; + const services = useKibana().services; + const { uiSettings, charts, data } = services; const { euiTheme } = useEuiTheme(); + const { hasAtLeast } = useLicense(); + const hasLogRateAnalysisLicense = hasAtLeast('platinum'); const [dataView, setDataView] = useState(); const [, setDataViewError] = useState(); const ruleParams = rule.params as RuleTypeParams & AlertParams; @@ -83,6 +87,7 @@ export default function AlertDetailsAppSection({ key={ALERT_TIME_RANGE_ANNOTATION_ID} />, ]; + useEffect(() => { setAlertSummaryFields([ { @@ -181,6 +186,9 @@ export default function AlertDetailsAppSection({ ))} + {hasLogRateAnalysisLicense && ( + + )} ) : null; diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/__snapshots__/log_rate_analysis_query.test.ts.snap b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/__snapshots__/log_rate_analysis_query.test.ts.snap new file mode 100644 index 0000000000000..9a9eb41224222 --- /dev/null +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/__snapshots__/log_rate_analysis_query.test.ts.snap @@ -0,0 +1,222 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`buildEsQuery should generate correct es query for rule with multiple metrics 1`] = `undefined`; + +exports[`buildEsQuery should generate correct es query for rule with optional filer, count filter and WITHOUT group by 1`] = ` +Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "optionalFilter": "container-1", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "host.name": "host-1", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "host.name": "host-2", + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, +} +`; + +exports[`buildEsQuery should generate correct es query for rule with optional filer, count filter and group by 1`] = ` +Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "optionalFilter": "container-1", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "host.name": "host-1", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "host.name": "host-2", + }, + }, + ], + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "groupByField": "groupByValue", + }, + }, + ], + }, + }, + ], + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, +} +`; + +exports[`buildEsQuery should generate correct es query for rule with optional filer, count filter and multiple group by 1`] = ` +Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "optionalFilter": "container-1", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "host.name": "host-1", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "host.name": "host-2", + }, + }, + ], + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "groupByField": "groupByValue", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "secondGroupByField": "secondGroupByValue", + }, + }, + ], + }, + }, + ], + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, +} +`; diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/get_initial_analysis_start.ts b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/get_initial_analysis_start.ts new file mode 100644 index 0000000000000..08bc835b7f43e --- /dev/null +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/get_initial_analysis_start.ts @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import moment, { Moment } from 'moment'; + +export interface GetInitialAnalysisStartArgs { + alertStart: Moment; + intervalFactor: number; + alertEnd?: Moment; +} + +export const getDeviationMax = ({ + alertStart, + intervalFactor, + alertEnd, +}: GetInitialAnalysisStartArgs) => { + if (alertEnd) { + return alertEnd + .clone() + .subtract(1 * intervalFactor, 'minutes') + .valueOf(); + } else if ( + alertStart + .clone() + .add(10 * intervalFactor, 'minutes') + .isAfter(moment(new Date())) + ) { + return moment(new Date()).valueOf(); + } else { + return alertStart + .clone() + .add(10 * intervalFactor, 'minutes') + .valueOf(); + } +}; + +export const getInitialAnalysisStart = (args: GetInitialAnalysisStartArgs) => { + const { alertStart, intervalFactor } = args; + return { + baselineMin: alertStart + .clone() + .subtract(13 * intervalFactor, 'minutes') + .valueOf(), + baselineMax: alertStart + .clone() + .subtract(2 * intervalFactor, 'minutes') + .valueOf(), + deviationMin: alertStart + .clone() + .subtract(1 * intervalFactor, 'minutes') + .valueOf(), + deviationMax: getDeviationMax(args), + }; +}; diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/log_rate_analysis_query.test.ts b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/log_rate_analysis_query.test.ts new file mode 100644 index 0000000000000..8169816800e4d --- /dev/null +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/log_rate_analysis_query.test.ts @@ -0,0 +1,98 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Aggregators, Comparator } from '../../../../../../common/custom_threshold_rule/types'; +import { CustomThresholdRuleTypeParams } from '../../../types'; +import { getLogRateAnalysisEQQuery } from './log_rate_analysis_query'; + +describe('buildEsQuery', () => { + const index = 'changedMockedIndex'; + const mockedParams: CustomThresholdRuleTypeParams = { + groupBy: ['host.hostname'], + searchConfiguration: { + index, + query: { query: 'optionalFilter: container-1', language: 'kuery' }, + }, + criteria: [ + { + metrics: [ + { + name: 'A', + aggType: Aggregators.COUNT, + filter: 'host.name: host-1 or host.name: host-2', + }, + ], + timeSize: 1, + timeUnit: 'm', + threshold: [90], + comparator: Comparator.GT, + }, + ], + }; + const mockedAlertWithMultipleGroups = { + fields: { + 'kibana.alert.group': [ + { + field: 'groupByField', + value: 'groupByValue', + }, + { + field: 'secondGroupByField', + value: 'secondGroupByValue', + }, + ], + }, + }; + const testData: Array<{ + title: string; + params: CustomThresholdRuleTypeParams; + alert: any; + }> = [ + { + title: 'rule with optional filer, count filter and group by', + params: mockedParams, + alert: { + fields: { + 'kibana.alert.group': [mockedAlertWithMultipleGroups.fields['kibana.alert.group'][0]], + }, + }, + }, + { + title: 'rule with optional filer, count filter and multiple group by', + params: mockedParams, + alert: mockedAlertWithMultipleGroups, + }, + { + title: 'rule with optional filer, count filter and WITHOUT group by', + params: mockedParams, + alert: {}, + }, + { + title: 'rule with multiple metrics', + params: { + ...mockedParams, + criteria: [ + { + metrics: [ + { name: 'A', aggType: Aggregators.COUNT, filter: 'host.name: host-1' }, + { name: 'B', aggType: Aggregators.AVERAGE, field: 'system.load.1' }, + ], + timeSize: 1, + timeUnit: 'm', + threshold: [90], + comparator: Comparator.GT, + }, + ], + }, + alert: {}, + }, + ]; + + test.each(testData)('should generate correct es query for $title', ({ alert, params }) => { + expect(getLogRateAnalysisEQQuery(alert, params)).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/log_rate_analysis_query.ts b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/log_rate_analysis_query.ts new file mode 100644 index 0000000000000..b9eef4643802a --- /dev/null +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/log_rate_analysis_query.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 { get } from 'lodash'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { Aggregators, GroupBy } from '../../../../../../common/custom_threshold_rule/types'; +import { buildEsQuery } from '../../../../../utils/build_es_query'; +import type { TopAlert } from '../../../../../typings/alerts'; +import type { CustomThresholdRuleTypeParams } from '../../../types'; +import type { CustomThresholdExpressionMetric } from '../../../../../../common/custom_threshold_rule/types'; + +const getKuery = ( + metrics: CustomThresholdExpressionMetric[], + filter?: string, + groupBy?: GroupBy +) => { + let query = ''; + const isOneCountConditionWithFilter = + metrics.length === 1 && metrics[0].aggType === 'count' && metrics[0].filter; + + if (filter && isOneCountConditionWithFilter) { + query = `(${filter}) and (${metrics[0].filter})`; + } else if (isOneCountConditionWithFilter) { + query = `(${metrics[0].filter!})`; + } else if (filter) { + query = `(${filter})`; + } + + if (groupBy) { + groupBy.forEach(({ field, value }) => { + query += ` and ${field}: ${value}`; + }); + } + + return query; +}; + +export const getLogRateAnalysisEQQuery = ( + alert: TopAlert>, + params: CustomThresholdRuleTypeParams +): QueryDslQueryContainer | undefined => { + // We only show log rate analysis for one condition with one count aggregation + if ( + params.criteria.length !== 1 || + params.criteria[0].metrics.length !== 1 || + params.criteria[0].metrics[0].aggType !== Aggregators.COUNT + ) { + return; + } + + const groupBy: GroupBy | undefined = get(alert, 'fields["kibana.alert.group"]'); + const optionalFilter: string | undefined = get(params.searchConfiguration, 'query.query'); + const boolQuery = buildEsQuery({ + kuery: getKuery(params.criteria[0].metrics, optionalFilter, groupBy), + }); + + return boolQuery; +}; diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/log_rate_analysis.tsx b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/log_rate_analysis.tsx new file mode 100644 index 0000000000000..7578f0979907f --- /dev/null +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section/log_rate_analysis.tsx @@ -0,0 +1,238 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { pick, orderBy } from 'lodash'; +import moment from 'moment'; +import React, { useEffect, useMemo, useState } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiTitle } from '@elastic/eui'; +import { + LOG_RATE_ANALYSIS_TYPE, + type LogRateAnalysisType, +} from '@kbn/aiops-utils/log_rate_analysis_type'; +import { LogRateAnalysisContent, type LogRateAnalysisResultsData } from '@kbn/aiops-plugin/public'; +import { Rule } from '@kbn/alerting-plugin/common'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { type Message, MessageRole } from '@kbn/observability-ai-assistant-plugin/public'; +import { ALERT_END } from '@kbn/rule-data-utils'; +import { CustomThresholdRuleTypeParams } from '../../types'; +import { TopAlert } from '../../../..'; +import { Color, colorTransformer } from '../../../../../common/custom_threshold_rule/color_palette'; +import { getLogRateAnalysisEQQuery } from './helpers/log_rate_analysis_query'; +import { getInitialAnalysisStart } from './helpers/get_initial_analysis_start'; + +export interface AlertDetailsLogRateAnalysisProps { + alert: TopAlert>; + dataView: any; + rule: Rule; + services: any; +} + +interface SignificantFieldValue { + field: string; + value: string | number; + docCount: number; + pValue: number | null; +} + +export function LogRateAnalysis({ + alert, + dataView, + rule, + services, +}: AlertDetailsLogRateAnalysisProps) { + const { + observabilityAIAssistant: { ObservabilityAIAssistantContextualInsight }, + } = services; + const [esSearchQuery, setEsSearchQuery] = useState(); + const [logRateAnalysisParams, setLogRateAnalysisParams] = useState< + | { logRateAnalysisType: LogRateAnalysisType; significantFieldValues: SignificantFieldValue[] } + | undefined + >(); + + useEffect(() => { + const esSearchRequest = getLogRateAnalysisEQQuery(alert, rule.params); + + if (esSearchRequest) { + setEsSearchQuery(esSearchRequest); + } + }, [alert, rule.params]); + + // Identify `intervalFactor` to adjust time ranges based on alert settings. + // The default time ranges for `initialAnalysisStart` are suitable for a `1m` lookback. + // If an alert would have a `5m` lookback, this would result in a factor of `5`. + const lookbackDuration = + alert.fields['kibana.alert.rule.parameters'] && + alert.fields['kibana.alert.rule.parameters'].timeSize && + alert.fields['kibana.alert.rule.parameters'].timeUnit + ? moment.duration( + alert.fields['kibana.alert.rule.parameters'].timeSize as number, + alert.fields['kibana.alert.rule.parameters'].timeUnit as any + ) + : moment.duration(1, 'm'); + const intervalFactor = Math.max(1, lookbackDuration.asSeconds() / 60); + + const alertStart = moment(alert.start); + const alertEnd = alert.fields[ALERT_END] ? moment(alert.fields[ALERT_END]) : undefined; + + const timeRange = { + min: alertStart.clone().subtract(15 * intervalFactor, 'minutes'), + max: alertEnd ? alertEnd.clone().add(1 * intervalFactor, 'minutes') : moment(new Date()), + }; + + const logRateAnalysisTitle = i18n.translate( + 'xpack.observability.customThreshold.alertDetails.logRateAnalysisTitle', + { + defaultMessage: 'Possible causes and remediations', + } + ); + + const onAnalysisCompleted = (analysisResults: LogRateAnalysisResultsData | undefined) => { + const significantFieldValues = orderBy( + analysisResults?.significantItems?.map((item) => ({ + field: item.fieldName, + value: item.fieldValue, + docCount: item.doc_count, + pValue: item.pValue, + })), + ['pValue', 'docCount'], + ['asc', 'asc'] + ).slice(0, 50); + + const logRateAnalysisType = analysisResults?.analysisType; + setLogRateAnalysisParams( + significantFieldValues && logRateAnalysisType + ? { logRateAnalysisType, significantFieldValues } + : undefined + ); + }; + + const messages = useMemo(() => { + const hasLogRateAnalysisParams = + logRateAnalysisParams && logRateAnalysisParams.significantFieldValues?.length > 0; + + if (!hasLogRateAnalysisParams) { + return undefined; + } + + const { logRateAnalysisType } = logRateAnalysisParams; + + const header = 'Field name,Field value,Doc count,p-value'; + const rows = logRateAnalysisParams.significantFieldValues + .map((item) => Object.values(item).join(',')) + .join('\n'); + + const content = `You are an observability expert using Elastic Observability Suite on call being consulted about a log threshold alert that got triggered by a ${logRateAnalysisType} in log messages. Your job is to take immediate action and proceed with both urgency and precision. + "Log Rate Analysis" is an AIOps feature that uses advanced statistical methods to identify reasons for increases and decreases in log rates. It makes it easy to find and investigate causes of unusual spikes or dips by using the analysis workflow view. + You are using "Log Rate Analysis" and ran the statistical analysis on the log messages which occured during the alert. + You received the following analysis results from "Log Rate Analysis" which list statistically significant co-occuring field/value combinations sorted from most significant (lower p-values) to least significant (higher p-values) that ${ + logRateAnalysisType === LOG_RATE_ANALYSIS_TYPE.SPIKE + ? 'contribute to the log rate spike' + : 'are less or not present in the log rate dip' + }: + + ${ + logRateAnalysisType === LOG_RATE_ANALYSIS_TYPE.SPIKE + ? 'The median log rate in the selected deviation time range is higher than the baseline. Therefore, the results shows statistically significant items within the deviation time range that are contributors to the spike. The "doc count" column refers to the amount of documents in the deviation time range.' + : 'The median log rate in the selected deviation time range is lower than the baseline. Therefore, the analysis results table shows statistically significant items within the baseline time range that are less in number or missing within the deviation time range. The "doc count" column refers to the amount of documents in the baseline time range.' + } + + ${header} + ${rows} + + Based on the above analysis results and your observability expert knowledge, output the following: + Analyse the type of these logs and explain their usual purpose (1 paragraph). + ${ + logRateAnalysisType === LOG_RATE_ANALYSIS_TYPE.SPIKE + ? 'Based on the type of these logs do a root cause analysis on why the field and value combinations from the analysis results are causing this log rate spike (2 parapraphs)' + : 'Based on the type of these logs explain why the statistically significant field and value combinations are less in number or missing from the log rate dip with concrete examples based on the analysis results data which contains items that are present in the baseline time range and are missing or less in number in the deviation time range (2 paragraphs)' + }. + ${ + logRateAnalysisType === LOG_RATE_ANALYSIS_TYPE.SPIKE + ? 'Recommend concrete remediations to resolve the root cause (3 bullet points).' + : '' + } + + Do not mention individual p-values from the analysis results. + Do not repeat the full list of field names and field values back to the user. + Do not guess, just say what you are sure of. Do not repeat the given instructions in your output.`; + + const now = new Date().toISOString(); + + return [ + { + '@timestamp': now, + message: { + content, + role: MessageRole.User, + }, + }, + ]; + }, [logRateAnalysisParams]); + + if (!dataView || !esSearchQuery) return null; + + return ( + + + + +

    + +

    +
    +
    + + + +
    + + {ObservabilityAIAssistantContextualInsight && messages ? ( + + + + ) : null} + +
    + ); +} diff --git a/x-pack/plugins/observability/public/components/custom_threshold/mocks/custom_threshold_rule.ts b/x-pack/plugins/observability/public/components/custom_threshold/mocks/custom_threshold_rule.ts index cfe41b6bd9d04..817e5dbadb978 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/mocks/custom_threshold_rule.ts +++ b/x-pack/plugins/observability/public/components/custom_threshold/mocks/custom_threshold_rule.ts @@ -8,7 +8,10 @@ import { v4 as uuidv4 } from 'uuid'; import { Aggregators, Comparator } from '../../../../common/custom_threshold_rule/types'; -import { CustomThresholdAlert, CustomThresholdRule } from '../components/alert_details_app_section'; +import { + CustomThresholdAlert, + CustomThresholdRule, +} from '../components/alert_details_app_section/alert_details_app_section'; export const buildCustomThresholdRule = ( rule: Partial = {} diff --git a/x-pack/plugins/observability/public/hooks/use_license.ts b/x-pack/plugins/observability/public/hooks/use_license.ts index f666dcd025bd3..f6ed1ebf8bab1 100644 --- a/x-pack/plugins/observability/public/hooks/use_license.ts +++ b/x-pack/plugins/observability/public/hooks/use_license.ts @@ -14,7 +14,7 @@ import { useKibana } from '../utils/kibana_react'; interface UseLicenseReturnValue { getLicense: () => ILicense | null; - hasAtLeast: (level: LicenseType) => boolean | undefined; + hasAtLeast: (level: LicenseType) => boolean; } export const useLicense = (): UseLicenseReturnValue => { @@ -25,7 +25,7 @@ export const useLicense = (): UseLicenseReturnValue => { getLicense: () => license, hasAtLeast: useCallback( (level: LicenseType) => { - if (!license) return; + if (!license) return false; return !!license && license.isAvailable && license.isActive && license.hasAtLeast(level); }, diff --git a/x-pack/plugins/observability/public/pages/overview/overview.tsx b/x-pack/plugins/observability/public/pages/overview/overview.tsx index 17121be51c668..5cc5e2ac967ea 100644 --- a/x-pack/plugins/observability/public/pages/overview/overview.tsx +++ b/x-pack/plugins/observability/public/pages/overview/overview.tsx @@ -73,8 +73,10 @@ export function OverviewPage() { const [esQuery, setEsQuery] = useState<{ bool: BoolQuery }>( buildEsQuery({ - from: relativeStart, - to: relativeEnd, + timeRange: { + from: relativeStart, + to: relativeEnd, + }, }) ); @@ -108,8 +110,10 @@ export function OverviewPage() { useEffect(() => { setEsQuery( buildEsQuery({ - from: relativeStart, - to: relativeEnd, + timeRange: { + from: relativeStart, + to: relativeEnd, + }, }) ); }, [relativeEnd, relativeStart]); @@ -117,8 +121,10 @@ export function OverviewPage() { const handleTimeRangeRefresh = useCallback(() => { setEsQuery( buildEsQuery({ - from: relativeStart, - to: relativeEnd, + timeRange: { + from: relativeStart, + to: relativeEnd, + }, }) ); }, [relativeEnd, relativeStart]); diff --git a/x-pack/plugins/observability/public/plugin.ts b/x-pack/plugins/observability/public/plugin.ts index 808573579cb99..03322f7817282 100644 --- a/x-pack/plugins/observability/public/plugin.ts +++ b/x-pack/plugins/observability/public/plugin.ts @@ -28,6 +28,7 @@ import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { LOG_EXPLORER_LOCATOR_ID, LogExplorerLocatorParams } from '@kbn/deeplinks-observability'; import type { DiscoverStart } from '@kbn/discover-plugin/public'; import type { EmbeddableStart } from '@kbn/embeddable-plugin/public'; +import type { FieldFormatsSetup, FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import type { HomePublicPluginSetup, HomePublicPluginStart } from '@kbn/home-plugin/public'; import { i18n } from '@kbn/i18n'; import type { LensPublicStart } from '@kbn/lens-plugin/public'; @@ -114,6 +115,7 @@ export interface ConfigSchema { export type ObservabilityPublicSetup = ReturnType; export interface ObservabilityPublicPluginsSetup { data: DataPublicPluginSetup; + fieldFormats: FieldFormatsSetup; observabilityShared: ObservabilitySharedPluginSetup; observabilityAIAssistant: ObservabilityAIAssistantPluginSetup; share: SharePluginSetup; @@ -137,6 +139,7 @@ export interface ObservabilityPublicPluginsStart { discover: DiscoverStart; embeddable: EmbeddableStart; exploratoryView: ExploratoryViewPublicStart; + fieldFormats: FieldFormatsStart; guidedOnboarding?: GuidedOnboardingPluginStart; lens: LensPublicStart; licensing: LicensingPluginStart; diff --git a/x-pack/plugins/observability/public/rules/register_observability_rule_types.ts b/x-pack/plugins/observability/public/rules/register_observability_rule_types.ts index c9079991bdf4d..04519eba23d5f 100644 --- a/x-pack/plugins/observability/public/rules/register_observability_rule_types.ts +++ b/x-pack/plugins/observability/public/rules/register_observability_rule_types.ts @@ -156,7 +156,10 @@ export const registerObservabilityRuleTypes = async ( }; }, alertDetailsAppSection: lazy( - () => import('../components/custom_threshold/components/alert_details_app_section') + () => + import( + '../components/custom_threshold/components/alert_details_app_section/alert_details_app_section' + ) ), priority: 5, }); diff --git a/x-pack/plugins/observability/public/utils/build_es_query/build_es_query.test.ts b/x-pack/plugins/observability/public/utils/build_es_query/build_es_query.test.ts index 4bbacaa7bb1ad..3cb37893e6169 100644 --- a/x-pack/plugins/observability/public/utils/build_es_query/build_es_query.test.ts +++ b/x-pack/plugins/observability/public/utils/build_es_query/build_es_query.test.ts @@ -37,6 +37,6 @@ describe('buildEsQuery', () => { ]; test.each(testData)('should generate correct es query for %j', ({ kuery, timeRange }) => { - expect(buildEsQuery(timeRange, kuery)).toMatchSnapshot(); + expect(buildEsQuery({ timeRange, kuery })).toMatchSnapshot(); }); }); diff --git a/x-pack/plugins/observability/public/utils/build_es_query/build_es_query.ts b/x-pack/plugins/observability/public/utils/build_es_query/build_es_query.ts index 1fd26690f86d5..acf6b4cfc4a7e 100644 --- a/x-pack/plugins/observability/public/utils/build_es_query/build_es_query.ts +++ b/x-pack/plugins/observability/public/utils/build_es_query/build_es_query.ts @@ -9,12 +9,14 @@ import { buildEsQuery as kbnBuildEsQuery, TimeRange, Query, EsQueryConfig } from import { ALERT_TIME_RANGE } from '@kbn/rule-data-utils'; import { getTime } from '@kbn/data-plugin/common'; -export function buildEsQuery( - timeRange: TimeRange, - kuery?: string, - queries: Query[] = [], - config: EsQueryConfig = {} -) { +interface BuildEsQueryArgs { + timeRange?: TimeRange; + kuery?: string; + queries?: Query[]; + config?: EsQueryConfig; +} + +export function buildEsQuery({ timeRange, kuery, queries = [], config = {} }: BuildEsQueryArgs) { const timeFilter = timeRange && getTime(undefined, timeRange, { diff --git a/x-pack/plugins/observability/server/lib/rules/custom_threshold/lib/evaluate_rule.ts b/x-pack/plugins/observability/server/lib/rules/custom_threshold/lib/evaluate_rule.ts index b1f790da9d146..f5b3f0adf1bdd 100644 --- a/x-pack/plugins/observability/server/lib/rules/custom_threshold/lib/evaluate_rule.ts +++ b/x-pack/plugins/observability/server/lib/rules/custom_threshold/lib/evaluate_rule.ts @@ -9,7 +9,8 @@ import moment from 'moment'; import { ElasticsearchClient } from '@kbn/core/server'; import type { Logger } from '@kbn/logging'; import { CustomMetricExpressionParams } from '../../../../../common/custom_threshold_rule/types'; -import { AdditionalContext, getIntervalInSeconds } from '../utils'; +import { getIntervalInSeconds } from '../../../../../common/utils/get_interval_in_seconds'; +import { AdditionalContext } from '../utils'; import { SearchConfigurationType } from '../types'; import { createTimerange } from './create_timerange'; import { getData } from './get_data'; diff --git a/x-pack/plugins/observability/server/lib/rules/custom_threshold/utils.ts b/x-pack/plugins/observability/server/lib/rules/custom_threshold/utils.ts index 66049ab431c5d..59d7cf93e0ea4 100644 --- a/x-pack/plugins/observability/server/lib/rules/custom_threshold/utils.ts +++ b/x-pack/plugins/observability/server/lib/rules/custom_threshold/utils.ts @@ -257,32 +257,6 @@ export const isTooManyBucketsPreviewException = ( ): value is TooManyBucketsPreviewExceptionMetadata => Boolean(value && value.TOO_MANY_BUCKETS_PREVIEW_EXCEPTION); -const intervalUnits = ['y', 'M', 'w', 'd', 'h', 'm', 's', 'ms']; -const INTERVAL_STRING_RE = new RegExp('^([0-9\\.]*)\\s*(' + intervalUnits.join('|') + ')$'); - -interface UnitsToSeconds { - [unit: string]: number; -} - -const units: UnitsToSeconds = { - ms: 0.001, - s: 1, - m: 60, - h: 3600, - d: 86400, - w: 86400 * 7, - M: 86400 * 30, - y: 86400 * 356, -}; - -export const getIntervalInSeconds = (interval: string): number => { - const matches = interval.match(INTERVAL_STRING_RE); - if (matches) { - return parseFloat(matches[1]) * units[matches[2]]; - } - throw new Error('Invalid interval string format.'); -}; - export const calculateRateTimeranges = (timerange: { to: number; from: number }) => { // This is the total number of milliseconds for the entire timerange const totalTime = timerange.to - timerange.from; diff --git a/x-pack/plugins/observability/tsconfig.json b/x-pack/plugins/observability/tsconfig.json index ba9ac59725adc..04f853572085f 100644 --- a/x-pack/plugins/observability/tsconfig.json +++ b/x-pack/plugins/observability/tsconfig.json @@ -102,7 +102,9 @@ "@kbn/core-elasticsearch-client-server-mocks", "@kbn/ingest-pipelines-plugin", "@kbn/core-saved-objects-api-server-mocks", - "@kbn/core-ui-settings-browser-mocks" + "@kbn/core-ui-settings-browser-mocks", + "@kbn/field-formats-plugin", + "@kbn/aiops-utils" ], "exclude": [ "target/**/*" From 42272f90c05616e1ea6bc4f80bc140f3a4979910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Fri, 5 Jan 2024 11:08:38 +0000 Subject: [PATCH 036/100] [Serverless Sidenav] Order active paths by tree depth (#174184) --- .../src/project_navigation/utils.test.ts | 55 ++++++++++--------- .../src/project_navigation/utils.ts | 3 + .../components/side_navigation/index.tsx | 2 - 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.test.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.test.ts index a207162e060cb..d886ee3a5d6ac 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.test.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.test.ts @@ -133,33 +133,36 @@ describe('findActiveNodes', () => { title: 'Root', path: 'root', }, + // Group 1 '[0][0]': { id: 'group1', title: 'Group 1', - deepLink: getDeepLink('group1', 'group1'), path: 'root.group1', }, '[0][0][0]': { - id: 'group1A', - title: 'Group 1A', - path: 'root.group1.group1A', - }, - '[0][0][0][0]': { id: 'item1', title: 'Item 1', - deepLink: getDeepLink('item1', 'item1'), - path: 'root.group1.group1A.item1', + deepLink: getDeepLink('item1', 'item1'), // First match + path: 'root.group1.item1', }, + // Group 2 '[0][1]': { id: 'group2', title: 'Group 2', + deepLink: getDeepLink('group2', 'group2'), path: 'root.group2', }, '[0][1][0]': { + id: 'group2A', + title: 'Group 2A', + path: 'root.group2.group2A', + }, + '[0][1][0][0]': { id: 'item2', title: 'Item 2', - deepLink: getDeepLink('item1', 'item1'), // Same link as above, should match both - path: 'root.group2.item2', + // Second match --> should come first as it is the longest match of the 2 + deepLink: getDeepLink('item1', 'item1'), + path: 'root.group2.group2A.item2', }, }; @@ -172,21 +175,21 @@ describe('findActiveNodes', () => { path: 'root', }, { - id: 'group1', - title: 'Group 1', - deepLink: getDeepLink('group1', 'group1'), - path: 'root.group1', + id: 'group2', + title: 'Group 2', + deepLink: getDeepLink('group2', 'group2'), + path: 'root.group2', }, { - id: 'group1A', - title: 'Group 1A', - path: 'root.group1.group1A', + id: 'group2A', + title: 'Group 2A', + path: 'root.group2.group2A', }, { - id: 'item1', - title: 'Item 1', + id: 'item2', + title: 'Item 2', deepLink: getDeepLink('item1', 'item1'), - path: 'root.group1.group1A.item1', + path: 'root.group2.group2A.item2', }, ], [ @@ -196,15 +199,15 @@ describe('findActiveNodes', () => { path: 'root', }, { - id: 'group2', - title: 'Group 2', - path: 'root.group2', + id: 'group1', + title: 'Group 1', + path: 'root.group1', }, { - id: 'item2', - title: 'Item 2', + id: 'item1', + title: 'Item 1', deepLink: getDeepLink('item1', 'item1'), - path: 'root.group2.item2', + path: 'root.group1.item1', }, ], ]); diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts index 63f7f8e612c2e..c025872d736b0 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts @@ -137,6 +137,9 @@ export const findActiveNodes = ( matches[length] = []; } matches[length].push(key); + // If there are multiple node matches of the same URL path length, we want to order them by + // tree depth, so that the longest match (deepest node) comes first. + matches[length].sort((a, b) => b.length - a.length); } } }); diff --git a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx index 5be456cfd5f3c..87e6dc3c7b567 100644 --- a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx +++ b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx @@ -33,8 +33,6 @@ const navigationTree: NavigationTreeDefinition = { defaultMessage: 'Discover', }), link: 'observability-log-explorer', - // prevent this entry from ever becoming active, effectively falling through to the obs-log-explorer child - getIsActive: () => false, // avoid duplicate "Discover" breadcrumbs breadcrumbStatus: 'hidden', renderAs: 'item', From 403a8d0604c1a3310470c7219a05c53017f27816 Mon Sep 17 00:00:00 2001 From: Carlos Crespo Date: Fri, 5 Jan 2024 12:30:12 +0100 Subject: [PATCH 037/100] [APM] Fix max bucket error in Dependencies pages (#173083) fixes: https://github.com/elastic/kibana/issues/161239 ## Summary This PR changes how dependencies data is fetched. To mitigate the max bucket error risk, and, at the same time, keep the compatibility with the dependencies-related pages that consume the `get_connection_stats` query, it now paginates the composite aggregation, using smaller batches of 1k items per pagination. **10k dependencies** image **500 dependencies per service** image **Notes:** Fetching 1k on each iteration might make the page slower; The max bucket error might still happen depending on the date range or how services are instrumented. ### How to test 1. Run synthtrace ``` node scripts/synthtrace service_many_dependencies.ts --from=now-15m --to=now --clean ``` 2. Navigate to the Dependencies Inventory page 3. Navigate to a service overview and then to the dependency tab --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../scenarios/service_many_dependencies.ts | 67 +++++++++ .../e2e/{ => dependencies}/dependencies.cy.ts | 50 ++++++- .../generate_many_dependencies.ts | 69 +++++++++ .../get_connection_stats/get_stats.ts | 140 ++++++++++-------- 4 files changed, 265 insertions(+), 61 deletions(-) create mode 100644 packages/kbn-apm-synthtrace/src/scenarios/service_many_dependencies.ts rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{ => dependencies}/dependencies.cy.ts (73%) create mode 100644 x-pack/plugins/apm/ftr_e2e/cypress/e2e/dependencies/generate_many_dependencies.ts diff --git a/packages/kbn-apm-synthtrace/src/scenarios/service_many_dependencies.ts b/packages/kbn-apm-synthtrace/src/scenarios/service_many_dependencies.ts new file mode 100644 index 0000000000000..a548e55f575a4 --- /dev/null +++ b/packages/kbn-apm-synthtrace/src/scenarios/service_many_dependencies.ts @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ApmFields, Instance } from '@kbn/apm-synthtrace-client'; +import { service } from '@kbn/apm-synthtrace-client/src/lib/apm/service'; +import { Scenario } from '../cli/scenario'; +import { RunOptions } from '../cli/utils/parse_run_cli_flags'; +import { getSynthtraceEnvironment } from '../lib/utils/get_synthtrace_environment'; +import { withClient } from '../lib/utils/with_client'; + +const ENVIRONMENT = getSynthtraceEnvironment(__filename); +const MAX_DEPENDENCIES = 10000; +const MAX_DEPENDENCIES_PER_SERVICE = 500; +const MAX_SERVICES = 20; + +const scenario: Scenario = async (runOptions: RunOptions) => { + return { + generate: ({ range, clients: { apmEsClient } }) => { + const javaInstances = Array.from({ length: MAX_SERVICES }).map((_, index) => + service(`opbeans-java-${index}`, ENVIRONMENT, 'java').instance(`java-instance-${index}`) + ); + + const instanceDependencies = (instance: Instance, startIndex: number) => { + const rate = range.ratePerMinute(60); + + return rate.generator((timestamp, index) => { + const currentIndex = index % MAX_DEPENDENCIES_PER_SERVICE; + const destination = (startIndex + currentIndex) % MAX_DEPENDENCIES; + + const span = instance + .transaction({ transactionName: 'GET /java' }) + .timestamp(timestamp) + .duration(400) + .success() + .children( + instance + .span({ + spanName: 'GET apm-*/_search', + spanType: 'db', + spanSubtype: 'elasticsearch', + }) + .destination(`elasticsearch/${destination}`) + .timestamp(timestamp) + .duration(200) + .success() + ); + + return span; + }); + }; + + return withClient( + apmEsClient, + javaInstances.map((instance, index) => + instanceDependencies(instance, (index * MAX_DEPENDENCIES_PER_SERVICE) % MAX_DEPENDENCIES) + ) + ); + }, + }; +}; + +export default scenario; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/dependencies.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/dependencies/dependencies.cy.ts similarity index 73% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/dependencies.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/dependencies/dependencies.cy.ts index 3200ba846fc76..11741c3d3066b 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/dependencies.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/dependencies/dependencies.cy.ts @@ -4,9 +4,10 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { synthtrace } from '../../synthtrace'; -import { opbeans } from '../fixtures/synthtrace/opbeans'; -import { checkA11y } from '../support/commands'; +import { synthtrace } from '../../../synthtrace'; +import { opbeans } from '../../fixtures/synthtrace/opbeans'; +import { checkA11y } from '../../support/commands'; +import { generateManyDependencies } from './generate_many_dependencies'; const start = '2021-10-10T00:00:00.000Z'; const end = '2021-10-10T00:15:00.000Z'; @@ -120,3 +121,46 @@ describe('Dependencies', () => { }); }); }); + +describe('Dependencies with high volume of data', () => { + before(() => { + synthtrace.index( + generateManyDependencies({ + from: new Date(start).getTime(), + to: new Date(end).getTime(), + }) + ); + }); + + after(() => { + synthtrace.clean(); + }); + + beforeEach(() => { + cy.loginAsViewerUser(); + }); + + it('shows dependencies inventory page', () => { + cy.visitKibana( + `/app/apm/dependencies/inventory?${new URLSearchParams({ + ...timeRange, + kuery: 'elasticsearch*', + })}` + ); + + cy.getByTestSubj('dependenciesTable'); + cy.contains('nav', 'Page 1 of 60'); + }); + + it('shows service dependencies', () => { + cy.visitKibana( + `/app/apm/services/synth-java-0/dependencies?${new URLSearchParams({ + ...timeRange, + })}` + ); + + cy.getByTestSubj('serviceDependenciesBreakdownChart').get('canvas'); + cy.getByTestSubj('dependenciesTable'); + cy.contains('nav', 'Page 1 of 100'); + }); +}); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/dependencies/generate_many_dependencies.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/dependencies/generate_many_dependencies.ts new file mode 100644 index 0000000000000..0389cd7f90b2f --- /dev/null +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/dependencies/generate_many_dependencies.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { apm, Instance, timerange } from '@kbn/apm-synthtrace-client'; + +const MAX_DEPENDENCIES = 10000; +const MAX_DEPENDENCIES_PER_SERVICE = 500; +const MAX_SERVICES = 20; + +export function generateManyDependencies({ + from, + to, +}: { + from: number; + to: number; +}) { + const instances = Array.from({ length: MAX_SERVICES }).map((_, index) => + apm + .service({ + name: `synth-java-${index}`, + environment: 'production', + agentName: 'java', + }) + .instance(`java-instance-${index}`) + ); + + const instanceDependencies = (instance: Instance, startIndex: number) => { + return Array.from( + timerange(new Date(from), new Date(to)) + .interval('1m') + .rate(60) + .generator((timestamp, index) => { + const currentIndex = index % MAX_DEPENDENCIES_PER_SERVICE; + const destination = (startIndex + currentIndex) % MAX_DEPENDENCIES; + + const span = instance + .transaction({ transactionName: 'GET /java' }) + .timestamp(timestamp) + .duration(400) + .success() + .children( + instance + .span({ + spanName: 'GET apm-*/_search', + spanType: 'db', + spanSubtype: 'elasticsearch', + }) + .destination(`elasticsearch/${destination}`) + .timestamp(timestamp) + .duration(200) + .success() + ); + + return span; + }) + ); + }; + + return instances.flatMap((instance, index) => + instanceDependencies( + instance, + (index * MAX_DEPENDENCIES_PER_SERVICE) % MAX_DEPENDENCIES + ) + ); +} diff --git a/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_stats.ts b/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_stats.ts index 4524d5121b78d..7dc038ef744c1 100644 --- a/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_stats.ts +++ b/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_stats.ts @@ -33,6 +33,7 @@ import { excludeRumExitSpansQuery } from '../exclude_rum_exit_spans_query'; import { APMEventClient } from '../../helpers/create_es_client/create_apm_event_client'; import { getDocumentTypeFilterForServiceDestinationStatistics } from '../../helpers/spans/get_is_using_service_destination_metrics'; +const MAX_ITEMS = 1500; export const getStats = async ({ apmEventClient, start, @@ -54,7 +55,85 @@ export const getStats = async ({ offset, }); - const response = await apmEventClient.search('get_connection_stats', { + const response = await getConnectionStats({ + apmEventClient, + startWithOffset, + endWithOffset, + filter, + numBuckets, + }); + + return ( + response.aggregations?.connections.buckets.map((bucket) => { + const sample = bucket.sample.top[0].metrics; + const serviceName = bucket.key.serviceName as string; + const dependencyName = bucket.key.dependencyName as string; + + return { + from: { + id: objectHash({ serviceName }), + serviceName, + environment: (sample[SERVICE_ENVIRONMENT] || + ENVIRONMENT_NOT_DEFINED.value) as string, + agentName: sample[AGENT_NAME] as AgentName, + type: NodeType.service as const, + }, + to: { + id: objectHash({ dependencyName }), + dependencyName, + spanType: sample[SPAN_TYPE] as string, + spanSubtype: (sample[SPAN_SUBTYPE] || '') as string, + type: NodeType.dependency as const, + }, + value: { + count: sum( + bucket.timeseries.buckets.map( + (dateBucket) => dateBucket.count.value ?? 0 + ) + ), + latency_sum: sum( + bucket.timeseries.buckets.map( + (dateBucket) => dateBucket.latency_sum.value ?? 0 + ) + ), + error_count: sum( + bucket.timeseries.buckets.flatMap( + (dateBucket) => + dateBucket[EVENT_OUTCOME].buckets.find( + (outcomeBucket) => outcomeBucket.key === EventOutcome.failure + )?.count.value ?? 0 + ) + ), + }, + timeseries: bucket.timeseries.buckets.map((dateBucket) => ({ + x: dateBucket.key + offsetInMs, + count: dateBucket.count.value ?? 0, + latency_sum: dateBucket.latency_sum.value ?? 0, + error_count: + dateBucket[EVENT_OUTCOME].buckets.find( + (outcomeBucket) => outcomeBucket.key === EventOutcome.failure + )?.count.value ?? 0, + })), + }; + }) ?? [] + ); +}; + +async function getConnectionStats({ + apmEventClient, + startWithOffset, + endWithOffset, + filter, + numBuckets, +}: { + apmEventClient: APMEventClient; + startWithOffset: number; + endWithOffset: number; + filter: QueryDslQueryContainer[]; + numBuckets: number; + after?: { serviceName: string | number; dependencyName: string | number }; +}) { + return apmEventClient.search('get_connection_stats', { apm: { sources: [ { @@ -79,7 +158,7 @@ export const getStats = async ({ aggs: { connections: { composite: { - size: 10000, + size: MAX_ITEMS, sources: asMutableArray([ { serviceName: { @@ -174,59 +253,4 @@ export const getStats = async ({ }, }, }); - - return ( - response.aggregations?.connections.buckets.map((bucket) => { - const sample = bucket.sample.top[0].metrics; - const serviceName = bucket.key.serviceName as string; - const dependencyName = bucket.key.dependencyName as string; - - return { - from: { - id: objectHash({ serviceName }), - serviceName, - environment: (sample[SERVICE_ENVIRONMENT] || - ENVIRONMENT_NOT_DEFINED.value) as string, - agentName: sample[AGENT_NAME] as AgentName, - type: NodeType.service as const, - }, - to: { - id: objectHash({ dependencyName }), - dependencyName, - spanType: sample[SPAN_TYPE] as string, - spanSubtype: (sample[SPAN_SUBTYPE] || '') as string, - type: NodeType.dependency as const, - }, - value: { - count: sum( - bucket.timeseries.buckets.map( - (dateBucket) => dateBucket.count.value ?? 0 - ) - ), - latency_sum: sum( - bucket.timeseries.buckets.map( - (dateBucket) => dateBucket.latency_sum.value ?? 0 - ) - ), - error_count: sum( - bucket.timeseries.buckets.flatMap( - (dateBucket) => - dateBucket[EVENT_OUTCOME].buckets.find( - (outcomeBucket) => outcomeBucket.key === EventOutcome.failure - )?.count.value ?? 0 - ) - ), - }, - timeseries: bucket.timeseries.buckets.map((dateBucket) => ({ - x: dateBucket.key + offsetInMs, - count: dateBucket.count.value ?? 0, - latency_sum: dateBucket.latency_sum.value ?? 0, - error_count: - dateBucket[EVENT_OUTCOME].buckets.find( - (outcomeBucket) => outcomeBucket.key === EventOutcome.failure - )?.count.value ?? 0, - })), - }; - }) ?? [] - ); -}; +} From 71db3d93e767645767c6df2d1b269fb83e7961c8 Mon Sep 17 00:00:00 2001 From: Katerina Date: Fri, 5 Jan 2024 13:58:46 +0200 Subject: [PATCH 038/100] [APM] Enable dashboard tab in mobile template (#174255) closes https://github.com/elastic/kibana/issues/174251 it should be consistent with the backend services. image --- .../actions/edit_dashboard.tsx | 3 +++ .../actions/link_dashboard.tsx | 3 +++ .../actions/save_dashboard_modal.tsx | 7 ++----- .../app/service_dashboards/index.tsx | 15 ++++++++++++--- .../routing/mobile_service_detail/index.tsx | 16 +++++++++++++++- .../mobile_service_template/index.tsx | 18 ++++++++++++++++-- 6 files changed, 51 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/service_dashboards/actions/edit_dashboard.tsx b/x-pack/plugins/apm/public/components/app/service_dashboards/actions/edit_dashboard.tsx index e3a6619b446d6..c880a912a5b51 100644 --- a/x-pack/plugins/apm/public/components/app/service_dashboards/actions/edit_dashboard.tsx +++ b/x-pack/plugins/apm/public/components/app/service_dashboards/actions/edit_dashboard.tsx @@ -13,9 +13,11 @@ import { MergedServiceDashboard } from '..'; export function EditDashboard({ onRefresh, currentDashboard, + serviceName, }: { onRefresh: () => void; currentDashboard: MergedServiceDashboard; + serviceName: string; }) { const [isModalVisible, setIsModalVisible] = useState(false); return ( @@ -37,6 +39,7 @@ export function EditDashboard({ onClose={() => setIsModalVisible(!isModalVisible)} onRefresh={onRefresh} currentDashboard={currentDashboard} + serviceName={serviceName} /> )} diff --git a/x-pack/plugins/apm/public/components/app/service_dashboards/actions/link_dashboard.tsx b/x-pack/plugins/apm/public/components/app/service_dashboards/actions/link_dashboard.tsx index 7b652c21039d8..0db2654c1d66b 100644 --- a/x-pack/plugins/apm/public/components/app/service_dashboards/actions/link_dashboard.tsx +++ b/x-pack/plugins/apm/public/components/app/service_dashboards/actions/link_dashboard.tsx @@ -14,10 +14,12 @@ export function LinkDashboard({ onRefresh, emptyButton = false, serviceDashboards, + serviceName, }: { onRefresh: () => void; emptyButton?: boolean; serviceDashboards?: MergedServiceDashboard[]; + serviceName: string; }) { const [isModalVisible, setIsModalVisible] = useState(false); @@ -51,6 +53,7 @@ export function LinkDashboard({ onClose={() => setIsModalVisible(false)} onRefresh={onRefresh} serviceDashboards={serviceDashboards} + serviceName={serviceName} /> )} diff --git a/x-pack/plugins/apm/public/components/app/service_dashboards/actions/save_dashboard_modal.tsx b/x-pack/plugins/apm/public/components/app/service_dashboards/actions/save_dashboard_modal.tsx index 3083e41c2dac2..6872b0d2cc805 100644 --- a/x-pack/plugins/apm/public/components/app/service_dashboards/actions/save_dashboard_modal.tsx +++ b/x-pack/plugins/apm/public/components/app/service_dashboards/actions/save_dashboard_modal.tsx @@ -28,7 +28,6 @@ import { callApmApi } from '../../../../services/rest/create_call_apm_api'; import { useDashboardFetcher } from '../../../../hooks/use_dashboards_fetcher'; import { FETCH_STATUS } from '../../../../hooks/use_fetcher'; import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; -import { useApmParams } from '../../../../hooks/use_apm_params'; import { SERVICE_NAME } from '../../../../../common/es_fields/apm'; import { fromQuery, toQuery } from '../../../shared/links/url_helpers'; import { MergedServiceDashboard } from '..'; @@ -38,6 +37,7 @@ interface Props { onRefresh: () => void; currentDashboard?: MergedServiceDashboard; serviceDashboards?: MergedServiceDashboard[]; + serviceName: string; } export function SaveDashboardModal({ @@ -45,6 +45,7 @@ export function SaveDashboardModal({ onRefresh, currentDashboard, serviceDashboards, + serviceName, }: Props) { const { core: { notifications }, @@ -71,10 +72,6 @@ export function SaveDashboardModal({ const isEditMode = !!currentDashboard?.id; - const { - path: { serviceName }, - } = useApmParams('/services/{serviceName}/dashboards'); - const reloadCustomDashboards = useCallback(() => { onRefresh(); }, [onRefresh]); diff --git a/x-pack/plugins/apm/public/components/app/service_dashboards/index.tsx b/x-pack/plugins/apm/public/components/app/service_dashboards/index.tsx index fe44d62c2388d..7426ec382b87f 100644 --- a/x-pack/plugins/apm/public/components/app/service_dashboards/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_dashboards/index.tsx @@ -28,7 +28,7 @@ import { SerializableRecord } from '@kbn/utility-types'; import { EmptyDashboards } from './empty_dashboards'; import { GotoDashboard, LinkDashboard } from './actions'; import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher'; -import { useApmParams } from '../../../hooks/use_apm_params'; +import { useAnyOfApmParams } from '../../../hooks/use_apm_params'; import { SavedApmCustomDashboard } from '../../../../common/custom_dashboards'; import { ContextMenu } from './context_menu'; import { UnlinkDashboard } from './actions/unlink_dashboard'; @@ -49,7 +49,10 @@ export function ServiceDashboards() { const { path: { serviceName }, query: { environment, kuery, rangeFrom, rangeTo, dashboardId }, - } = useApmParams('/services/{serviceName}/dashboards'); + } = useAnyOfApmParams( + '/services/{serviceName}/dashboards', + '/mobile-services/{serviceName}/dashboards' + ); const [dashboard, setDashboard] = useState(); const [serviceDashboards, setServiceDashboards] = useState< MergedServiceDashboard[] @@ -209,11 +212,13 @@ export function ServiceDashboards() { emptyButton={true} onRefresh={refetch} serviceDashboards={serviceDashboards} + serviceName={serviceName} />, , , ) : ( - } /> + + } + /> )} ); diff --git a/x-pack/plugins/apm/public/components/routing/mobile_service_detail/index.tsx b/x-pack/plugins/apm/public/components/routing/mobile_service_detail/index.tsx index 11a365e0d8328..fa8e7ee0323ab 100644 --- a/x-pack/plugins/apm/public/components/routing/mobile_service_detail/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/mobile_service_detail/index.tsx @@ -26,7 +26,7 @@ import { ErrorGroupDetails } from '../../app/mobile/errors_and_crashes_group_det import { CrashGroupDetails } from '../../app/mobile/errors_and_crashes_group_details/crash_group_details'; import { MobileErrorCrashesOverview } from '../../app/mobile/errors_and_crashes_overview'; import { ServiceDependencies } from '../../app/service_dependencies'; - +import { ServiceDashboards } from '../../app/service_dashboards'; export function page({ title, tabKey, @@ -270,6 +270,20 @@ export const mobileServiceDetailRoute = { }), }), }, + '/mobile-services/{serviceName}/dashboards': { + ...page({ + tabKey: 'dashboards', + title: i18n.translate('xpack.apm.views.dashboard.title', { + defaultMessage: 'Dashboards', + }), + element: , + }), + params: t.partial({ + query: t.partial({ + dashboardId: t.string, + }), + }), + }, '/mobile-services/{serviceName}/': { element: , }, diff --git a/x-pack/plugins/apm/public/components/routing/templates/mobile_service_template/index.tsx b/x-pack/plugins/apm/public/components/routing/templates/mobile_service_template/index.tsx index 3c9bde66ff3ac..b5ce69d9c1d03 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/mobile_service_template/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/mobile_service_template/index.tsx @@ -35,7 +35,8 @@ type Tab = NonNullable[0] & { | 'dependencies' | 'errors-and-crashes' | 'service-map' - | 'alerts'; + | 'alerts' + | 'dashboards'; hidden?: boolean; }; @@ -231,12 +232,25 @@ function useTabs({ selectedTabKey }: { selectedTabKey: Tab['key'] }) { path: { serviceName }, query, }), - append: , label: i18n.translate('xpack.apm.mobileServiceDetails.alertsTabLabel', { defaultMessage: 'Alerts', }), hidden: !(isAlertingAvailable && canReadAlerts), }, + { + key: 'dashboards', + href: router.link('/mobile-services/{serviceName}/dashboards', { + path: { serviceName }, + query, + }), + append: , + label: i18n.translate( + 'xpack.apm.mobileServiceDetails.dashboardsTabLabel', + { + defaultMessage: 'Dashboards', + } + ), + }, ]; return tabs From c39fac616b7413cc21fe17838025a443e60fdc69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20C=C3=B4t=C3=A9?= Date: Fri, 5 Jan 2024 08:01:59 -0500 Subject: [PATCH 039/100] Rename connector compatibility for Generative AI so it is split between security and o11y (#174000) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this PR, I'm renaming `Generative AI` to `Generative AI for Security` in the connectors comatibility list so we have a split on Gen AI for Security and Observability (follow up from https://github.com/elastic/kibana/pull/173826). ## Screenshots Screenshot 2024-01-03 at 11 53 00 AM Screenshot 2024-01-03 at 11 53 32 AM Screenshot 2024-01-03 at 11 53 39 AM ## To verify **Connectors** 1. Startup Kibana in trial mode 2. Open the create Bedrock connector flyout from the connectors page 3. Notice the compatibility is only for Security 4. Create a Bedrock connector (input random text in all fields to pass validation) 5. Open the create OpenAI connector from the connectors page 6. Notice the compatibility is for Security and Observability 7. Create an OpenAI connector (input random text in all fields to pass validation) **Security Solution** 9. Navigate to the Security solution (`/app/security/get_started`) 10. Open the AI Assistant on the top right 11. Open the `Conversation Settings` 12. See OpenAI and Bedrock connectors displaying **Observability** 13. Navigate to the Observability app (`/app/observability/overview`) 14. Open the AI Assistant on the top right 15. Select the actions menu on the top right of the flyout and open `AI Assistant Settings` 16. Open the default connector dropdown 17. Notice only OpenAI connectors displaying --- .../use_load_action_types/index.test.tsx | 2 +- .../use_load_action_types/index.tsx | 4 ++-- .../common/connector_feature_config.test.ts | 6 +++--- .../common/connector_feature_config.ts | 20 +++++++++---------- x-pack/plugins/actions/common/types.ts | 2 +- .../server/connector_types/bedrock/index.ts | 4 ++-- .../server/connector_types/openai/index.ts | 4 ++-- .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 10 files changed, 21 insertions(+), 24 deletions(-) diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/use_load_action_types/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/use_load_action_types/index.test.tsx index 0aa6ed21e2f88..50d3a73797413 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/use_load_action_types/index.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/use_load_action_types/index.test.tsx @@ -37,7 +37,7 @@ describe('useLoadActionTypes', () => { await waitForNextUpdate(); expect(defaultProps.http.get).toHaveBeenCalledWith('/api/actions/connector_types', { - query: { feature_id: 'generativeAI' }, + query: { feature_id: 'generativeAIForSecurity' }, }); expect(toasts.addError).not.toHaveBeenCalled(); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/use_load_action_types/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/use_load_action_types/index.tsx index d307f85e43b7f..cf62127f286ca 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/use_load_action_types/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/use_load_action_types/index.tsx @@ -15,7 +15,7 @@ import type { IHttpFetchError } from '@kbn/core-http-browser'; import type { ActionType } from '@kbn/actions-plugin/common'; import { HttpSetup } from '@kbn/core-http-browser'; import { IToasts } from '@kbn/core-notifications-browser'; -import { GenerativeAIConnectorFeatureId } from '@kbn/actions-plugin/common'; +import { GenerativeAIForSecurityConnectorFeatureId } from '@kbn/actions-plugin/common'; import * as i18n from '../translations'; /** @@ -39,7 +39,7 @@ export const useLoadActionTypes = ({ async () => { const queryResult = await loadActionTypes({ http, - featureId: GenerativeAIConnectorFeatureId, + featureId: GenerativeAIForSecurityConnectorFeatureId, }); const sortedData = queryResult.sort((a, b) => a.name.localeCompare(b.name)); diff --git a/x-pack/plugins/actions/common/connector_feature_config.test.ts b/x-pack/plugins/actions/common/connector_feature_config.test.ts index c12e3db21127f..1f18e923593d5 100644 --- a/x-pack/plugins/actions/common/connector_feature_config.test.ts +++ b/x-pack/plugins/actions/common/connector_feature_config.test.ts @@ -13,7 +13,7 @@ import { describe('areValidFeatures', () => { it('returns true when all inputs are valid features', () => { - expect(areValidFeatures(['alerting', 'cases', 'generativeAI'])).toBeTruthy(); + expect(areValidFeatures(['alerting', 'cases', 'generativeAIForSecurity'])).toBeTruthy(); }); it('returns true when only one input and it is a valid feature', () => { @@ -43,8 +43,8 @@ describe('getConnectorFeatureName', () => { describe('getConnectorCompatibility', () => { it('returns the compatibility list for valid feature ids', () => { expect( - getConnectorCompatibility(['alerting', 'cases', 'uptime', 'siem', 'generativeAI']) - ).toEqual(['Alerting Rules', 'Cases', 'Generative AI']); + getConnectorCompatibility(['alerting', 'cases', 'uptime', 'siem', 'generativeAIForSecurity']) + ).toEqual(['Alerting Rules', 'Cases', 'Generative AI for Security']); }); it('skips invalid feature ids', () => { diff --git a/x-pack/plugins/actions/common/connector_feature_config.ts b/x-pack/plugins/actions/common/connector_feature_config.ts index fb61ff35da6b7..4638387d31c5e 100644 --- a/x-pack/plugins/actions/common/connector_feature_config.ts +++ b/x-pack/plugins/actions/common/connector_feature_config.ts @@ -25,20 +25,20 @@ export const AlertingConnectorFeatureId = 'alerting'; export const CasesConnectorFeatureId = 'cases'; export const UptimeConnectorFeatureId = 'uptime'; export const SecurityConnectorFeatureId = 'siem'; -export const GenerativeAIConnectorFeatureId = 'generativeAI'; +export const GenerativeAIForSecurityConnectorFeatureId = 'generativeAIForSecurity'; export const GenerativeAIForObservabilityConnectorFeatureId = 'generativeAIForObservability'; -const compatibilityGenerativeAI = i18n.translate( - 'xpack.actions.availableConnectorFeatures.compatibility.generativeAI', +const compatibilityGenerativeAIForSecurity = i18n.translate( + 'xpack.actions.availableConnectorFeatures.compatibility.generativeAIForSecurity', { - defaultMessage: 'Generative AI', + defaultMessage: 'Generative AI for Security', } ); const compatibilityGenerativeAIForObservability = i18n.translate( 'xpack.actions.availableConnectorFeatures.compatibility.generativeAIForObservability', { - defaultMessage: 'Generative AI For Observability', + defaultMessage: 'Generative AI for Observability', } ); @@ -88,10 +88,10 @@ export const SecuritySolutionFeature: ConnectorFeatureConfig = { compatibility: compatibilityAlertingRules, }; -export const GenerativeAIFeature: ConnectorFeatureConfig = { - id: GenerativeAIConnectorFeatureId, - name: compatibilityGenerativeAI, - compatibility: compatibilityGenerativeAI, +export const GenerativeAIForSecurityFeature: ConnectorFeatureConfig = { + id: GenerativeAIForSecurityConnectorFeatureId, + name: compatibilityGenerativeAIForSecurity, + compatibility: compatibilityGenerativeAIForSecurity, }; export const GenerativeAIForObservabilityFeature: ConnectorFeatureConfig = { @@ -105,7 +105,7 @@ const AllAvailableConnectorFeatures = { [CasesConnectorFeature.id]: CasesConnectorFeature, [UptimeConnectorFeature.id]: UptimeConnectorFeature, [SecuritySolutionFeature.id]: SecuritySolutionFeature, - [GenerativeAIFeature.id]: GenerativeAIFeature, + [GenerativeAIForSecurityFeature.id]: GenerativeAIForSecurityFeature, [GenerativeAIForObservabilityFeature.id]: GenerativeAIForObservabilityFeature, }; diff --git a/x-pack/plugins/actions/common/types.ts b/x-pack/plugins/actions/common/types.ts index 2560cbae3f7e7..7420240d71cc0 100644 --- a/x-pack/plugins/actions/common/types.ts +++ b/x-pack/plugins/actions/common/types.ts @@ -13,7 +13,7 @@ export { CasesConnectorFeatureId, UptimeConnectorFeatureId, SecurityConnectorFeatureId, - GenerativeAIConnectorFeatureId, + GenerativeAIForSecurityConnectorFeatureId, } from './connector_feature_config'; export interface ActionType { id: string; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/index.ts index e9ab583277282..5f295b8c39367 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/index.ts @@ -10,7 +10,7 @@ import { SubActionConnectorType, ValidatorType, } from '@kbn/actions-plugin/server/sub_action_framework/types'; -import { GenerativeAIConnectorFeatureId } from '@kbn/actions-plugin/common'; +import { GenerativeAIForSecurityConnectorFeatureId } from '@kbn/actions-plugin/common'; import { urlAllowListValidator } from '@kbn/actions-plugin/server'; import { ValidatorServices } from '@kbn/actions-plugin/server/types'; import { assertURL } from '@kbn/actions-plugin/server/sub_action_framework/helpers/validators'; @@ -29,7 +29,7 @@ export const getConnectorType = (): SubActionConnectorType => ( secrets: SecretsSchema, }, validators: [{ type: ValidatorType.CONFIG, validator: configValidator }], - supportedFeatureIds: [GenerativeAIConnectorFeatureId], + supportedFeatureIds: [GenerativeAIForSecurityConnectorFeatureId], minimumLicenseRequired: 'enterprise' as const, renderParameterTemplates, }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/index.ts index 6852a83a9ee3f..3fa865209ba5c 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/index.ts @@ -11,7 +11,7 @@ import { ValidatorType, } from '@kbn/actions-plugin/server/sub_action_framework/types'; import { - GenerativeAIConnectorFeatureId, + GenerativeAIForSecurityConnectorFeatureId, GenerativeAIForObservabilityConnectorFeatureId, } from '@kbn/actions-plugin/common'; import { urlAllowListValidator } from '@kbn/actions-plugin/server'; @@ -37,7 +37,7 @@ export const getConnectorType = (): SubActionConnectorType => ( }, validators: [{ type: ValidatorType.CONFIG, validator: configValidator }], supportedFeatureIds: [ - GenerativeAIConnectorFeatureId, + GenerativeAIForSecurityConnectorFeatureId, GenerativeAIForObservabilityConnectorFeatureId, ], minimumLicenseRequired: 'enterprise' as const, diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index e7fa92aa02a3c..e8365d42168ae 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -7621,7 +7621,6 @@ "xpack.actions.availableConnectorFeatures.cases": "Cas", "xpack.actions.availableConnectorFeatures.compatibility.alertingRules": "Règles d'alerting", "xpack.actions.availableConnectorFeatures.compatibility.cases": "Cas", - "xpack.actions.availableConnectorFeatures.compatibility.generativeAI": "IA générative", "xpack.actions.availableConnectorFeatures.securitySolution": "Solution de sécurité", "xpack.actions.availableConnectorFeatures.uptime": "Uptime", "xpack.actions.builtin.cases.jiraTitle": "Jira", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 4a23239256f53..bf36677dd19e6 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -7636,7 +7636,6 @@ "xpack.actions.availableConnectorFeatures.cases": "ケース", "xpack.actions.availableConnectorFeatures.compatibility.alertingRules": "アラートルール", "xpack.actions.availableConnectorFeatures.compatibility.cases": "ケース", - "xpack.actions.availableConnectorFeatures.compatibility.generativeAI": "生成AI", "xpack.actions.availableConnectorFeatures.securitySolution": "セキュリティソリューション", "xpack.actions.availableConnectorFeatures.uptime": "アップタイム", "xpack.actions.builtin.cases.jiraTitle": "Jira", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index ccce90db35aaf..ebc2118a79b70 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -7702,7 +7702,6 @@ "xpack.actions.availableConnectorFeatures.cases": "案例", "xpack.actions.availableConnectorFeatures.compatibility.alertingRules": "告警规则", "xpack.actions.availableConnectorFeatures.compatibility.cases": "案例", - "xpack.actions.availableConnectorFeatures.compatibility.generativeAI": "生成式 AI", "xpack.actions.availableConnectorFeatures.securitySolution": "安全解决方案", "xpack.actions.availableConnectorFeatures.uptime": "运行时间", "xpack.actions.builtin.cases.jiraTitle": "Jira", From b37634d2b70c6ae99a1b3da9f8a529c112f557ef Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Fri, 5 Jan 2024 15:19:14 +0200 Subject: [PATCH 040/100] [Lens][Inline editing] Improve the api for the embeddable consumers (#173841) ## Summary Closes https://github.com/elastic/kibana/issues/167632 This PR provides a simpler api for the Lens embeddable consumers who want to provide inline editing capabilities. I added an example to help with the integration. Run kibana with ``` yarn start --run-examples ``` http://localhost:5601/app/lens_embeddable_inline_editing_example image image It also allows the consumers to render the inline editing component in a custom element in case you don't want to open a push flyout. ![custom-container](https://github.com/elastic/kibana/assets/17003240/6ce1b9c6-dab0-4321-b4c0-ae196dfb4a84) I included a readme on how to use the api. ### Note This is the first PR which uses the new Lens config builder so some of the changes are not related to the api improvements but they are fixing some bugs on the builder. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .github/CODEOWNERS | 1 + package.json | 1 + .../lens_attributes_builder.test.ts | 46 ++--- .../config_builder/charts/gauge.test.ts | 3 - .../config_builder/charts/heatmap.test.ts | 3 - .../config_builder/charts/metric.test.ts | 3 - .../config_builder/charts/partition.test.ts | 3 - .../config_builder/charts/region_map.test.ts | 3 - .../config_builder/charts/table.test.ts | 3 - .../config_builder/charts/tag_cloud.test.ts | 3 - .../config_builder/charts/xy.test.ts | 3 - .../config_builder/utils.test.ts | 3 - .../config_builder/utils.ts | 14 +- packages/kbn-optimizer/limits.yml | 2 +- .../group_preview.test.tsx | 2 +- .../group_editor_flyout/lens_attributes.ts | 2 +- tsconfig.base.json | 2 + .../.eslintrc.json | 5 + .../README.md | 68 +++++++ .../kibana.jsonc | 21 ++ .../public/app.tsx | 182 ++++++++++++++++++ .../public/embeddable.tsx | 161 ++++++++++++++++ .../public/flyout.tsx | 124 ++++++++++++ .../public/image.png | Bin 0 -> 155151 bytes .../public/index.ts | 10 + .../public/mount.tsx | 49 +++++ .../public/plugin.ts | 57 ++++++ .../public/utils.ts | 63 ++++++ .../tsconfig.json | 26 +++ .../configurations/lens_attributes.test.ts | 2 +- .../get_edit_lens_configuration.tsx | 4 + .../lens_configuration_flyout.tsx | 6 + .../shared/edit_on_the_fly/types.ts | 4 + x-pack/plugins/lens/public/async_services.ts | 1 + .../embeddable/embeddable_component.tsx | 2 +- x-pack/plugins/lens/public/index.ts | 2 + x-pack/plugins/lens/public/plugin.ts | 18 ++ .../in_app_embeddable_edit_action.test.tsx | 97 ++++++++++ .../in_app_embeddable_edit_action.tsx | 64 ++++++ .../in_app_embeddable_edit_action_helpers.tsx | 154 +++++++++++++++ .../in_app_embeddable_edit_trigger.ts | 19 ++ .../in_app_embeddable_edit/types.ts | 37 ++++ x-pack/plugins/lens/readme.md | 8 + .../risk_summary_flyout/risk_summary.test.tsx | 8 +- yarn.lock | 3 + 45 files changed, 1223 insertions(+), 69 deletions(-) create mode 100644 x-pack/examples/lens_embeddable_inline_editing_example/.eslintrc.json create mode 100644 x-pack/examples/lens_embeddable_inline_editing_example/README.md create mode 100644 x-pack/examples/lens_embeddable_inline_editing_example/kibana.jsonc create mode 100644 x-pack/examples/lens_embeddable_inline_editing_example/public/app.tsx create mode 100644 x-pack/examples/lens_embeddable_inline_editing_example/public/embeddable.tsx create mode 100644 x-pack/examples/lens_embeddable_inline_editing_example/public/flyout.tsx create mode 100644 x-pack/examples/lens_embeddable_inline_editing_example/public/image.png create mode 100644 x-pack/examples/lens_embeddable_inline_editing_example/public/index.ts create mode 100644 x-pack/examples/lens_embeddable_inline_editing_example/public/mount.tsx create mode 100644 x-pack/examples/lens_embeddable_inline_editing_example/public/plugin.ts create mode 100644 x-pack/examples/lens_embeddable_inline_editing_example/public/utils.ts create mode 100644 x-pack/examples/lens_embeddable_inline_editing_example/tsconfig.json create mode 100644 x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action.test.tsx create mode 100644 x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action.tsx create mode 100644 x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action_helpers.tsx create mode 100644 x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_trigger.ts create mode 100644 x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b3d2e9cf82ad4..4dae217dce6ad 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -487,6 +487,7 @@ x-pack/plugins/kubernetes_security @elastic/kibana-cloud-security-posture packages/kbn-language-documentation-popover @elastic/kibana-visualizations packages/kbn-lens-embeddable-utils @elastic/obs-ux-infra_services-team @elastic/kibana-visualizations packages/kbn-lens-formula-docs @elastic/kibana-visualizations +x-pack/examples/lens_embeddable_inline_editing_example @elastic/kibana-visualizations x-pack/plugins/lens @elastic/kibana-visualizations x-pack/plugins/license_api_guard @elastic/platform-deployment-management x-pack/plugins/license_management @elastic/platform-deployment-management diff --git a/package.json b/package.json index 4f6aef817d579..0a4d9ebfcebdb 100644 --- a/package.json +++ b/package.json @@ -509,6 +509,7 @@ "@kbn/language-documentation-popover": "link:packages/kbn-language-documentation-popover", "@kbn/lens-embeddable-utils": "link:packages/kbn-lens-embeddable-utils", "@kbn/lens-formula-docs": "link:packages/kbn-lens-formula-docs", + "@kbn/lens-inline-editing-example-plugin": "link:x-pack/examples/lens_embeddable_inline_editing_example", "@kbn/lens-plugin": "link:x-pack/plugins/lens", "@kbn/license-api-guard-plugin": "link:x-pack/plugins/license_api_guard", "@kbn/license-management-plugin": "link:x-pack/plugins/license_management", diff --git a/packages/kbn-lens-embeddable-utils/attribute_builder/lens_attributes_builder.test.ts b/packages/kbn-lens-embeddable-utils/attribute_builder/lens_attributes_builder.test.ts index 199379e74eb9d..2f90e03099350 100644 --- a/packages/kbn-lens-embeddable-utils/attribute_builder/lens_attributes_builder.test.ts +++ b/packages/kbn-lens-embeddable-utils/attribute_builder/lens_attributes_builder.test.ts @@ -113,15 +113,13 @@ describe('lens_attributes_builder', () => { formulaAPI, }); const builder = new LensAttributesBuilder({ visualization: metriChart }); + const { - state: { - datasourceStates: { - formBased: { layers }, - }, - visualization, - }, + state: { datasourceStates: datasourceStates, visualization }, } = builder.build(); + const layers = datasourceStates.formBased?.layers; + expect(layers).toEqual({ layer: { columnOrder: ['metric_formula_accessor'], @@ -156,14 +154,11 @@ describe('lens_attributes_builder', () => { }); const builder = new LensAttributesBuilder({ visualization: metriChart }); const { - state: { - datasourceStates: { - formBased: { layers }, - }, - visualization, - }, + state: { datasourceStates: datasourceStates, visualization }, } = builder.build(); + const layers = datasourceStates.formBased?.layers; + expect(layers).toEqual({ layer: { columnOrder: ['metric_formula_accessor'], @@ -215,14 +210,11 @@ describe('lens_attributes_builder', () => { }); const builder = new LensAttributesBuilder({ visualization: xyChart }); const { - state: { - datasourceStates: { - formBased: { layers }, - }, - visualization, - }, + state: { datasourceStates: datasourceStates, visualization }, } = builder.build(); + const layers = datasourceStates.formBased?.layers; + expect(layers).toEqual({ layer_0: { columnOrder: ['x_date_histogram', 'formula_accessor_0_0'], @@ -272,14 +264,11 @@ describe('lens_attributes_builder', () => { }); const builder = new LensAttributesBuilder({ visualization: xyChart }); const { - state: { - datasourceStates: { - formBased: { layers }, - }, - visualization, - }, + state: { datasourceStates: datasourceStates, visualization }, } = builder.build(); + const layers = datasourceStates.formBased?.layers; + expect(layers).toEqual({ layer_0: { columnOrder: ['x_date_histogram', 'formula_accessor_0_0'], @@ -340,14 +329,11 @@ describe('lens_attributes_builder', () => { }); const builder = new LensAttributesBuilder({ visualization: xyChart }); const { - state: { - datasourceStates: { - formBased: { layers }, - }, - visualization, - }, + state: { datasourceStates: datasourceStates, visualization }, } = builder.build(); + const layers = datasourceStates.formBased?.layers; + expect(layers).toEqual({ layer_0: { columnOrder: ['x_date_histogram', 'formula_accessor_0_0', 'formula_accessor_0_1'], diff --git a/packages/kbn-lens-embeddable-utils/config_builder/charts/gauge.test.ts b/packages/kbn-lens-embeddable-utils/config_builder/charts/gauge.test.ts index 5e0e5dc1de2a7..aa13813e37b82 100644 --- a/packages/kbn-lens-embeddable-utils/config_builder/charts/gauge.test.ts +++ b/packages/kbn-lens-embeddable-utils/config_builder/charts/gauge.test.ts @@ -79,9 +79,6 @@ test('generates gauge chart config', async () => { "test": Object {}, }, "datasourceStates": Object { - "formBased": Object { - "layers": Object {}, - }, "textBased": Object { "layers": Object { "layer_0": Object { diff --git a/packages/kbn-lens-embeddable-utils/config_builder/charts/heatmap.test.ts b/packages/kbn-lens-embeddable-utils/config_builder/charts/heatmap.test.ts index cfcabb131b451..91786a0b91e23 100644 --- a/packages/kbn-lens-embeddable-utils/config_builder/charts/heatmap.test.ts +++ b/packages/kbn-lens-embeddable-utils/config_builder/charts/heatmap.test.ts @@ -81,9 +81,6 @@ test('generates metric chart config', async () => { "test": Object {}, }, "datasourceStates": Object { - "formBased": Object { - "layers": Object {}, - }, "textBased": Object { "layers": Object { "layer_0": Object { diff --git a/packages/kbn-lens-embeddable-utils/config_builder/charts/metric.test.ts b/packages/kbn-lens-embeddable-utils/config_builder/charts/metric.test.ts index cf82d3a2f5f4d..86078332ebb42 100644 --- a/packages/kbn-lens-embeddable-utils/config_builder/charts/metric.test.ts +++ b/packages/kbn-lens-embeddable-utils/config_builder/charts/metric.test.ts @@ -79,9 +79,6 @@ test('generates metric chart config', async () => { "test": Object {}, }, "datasourceStates": Object { - "formBased": Object { - "layers": Object {}, - }, "textBased": Object { "layers": Object { "layer_0": Object { diff --git a/packages/kbn-lens-embeddable-utils/config_builder/charts/partition.test.ts b/packages/kbn-lens-embeddable-utils/config_builder/charts/partition.test.ts index 22ee18f3e5f3e..120b3069552d8 100644 --- a/packages/kbn-lens-embeddable-utils/config_builder/charts/partition.test.ts +++ b/packages/kbn-lens-embeddable-utils/config_builder/charts/partition.test.ts @@ -80,9 +80,6 @@ test('generates metric chart config', async () => { "test": Object {}, }, "datasourceStates": Object { - "formBased": Object { - "layers": Object {}, - }, "textBased": Object { "layers": Object { "layer_0": Object { diff --git a/packages/kbn-lens-embeddable-utils/config_builder/charts/region_map.test.ts b/packages/kbn-lens-embeddable-utils/config_builder/charts/region_map.test.ts index 0093b03e33bc3..4fd97797b69dd 100644 --- a/packages/kbn-lens-embeddable-utils/config_builder/charts/region_map.test.ts +++ b/packages/kbn-lens-embeddable-utils/config_builder/charts/region_map.test.ts @@ -80,9 +80,6 @@ test('generates metric chart config', async () => { "test": Object {}, }, "datasourceStates": Object { - "formBased": Object { - "layers": Object {}, - }, "textBased": Object { "layers": Object { "layer_0": Object { diff --git a/packages/kbn-lens-embeddable-utils/config_builder/charts/table.test.ts b/packages/kbn-lens-embeddable-utils/config_builder/charts/table.test.ts index 909f3e737ac99..dbe67d15416c4 100644 --- a/packages/kbn-lens-embeddable-utils/config_builder/charts/table.test.ts +++ b/packages/kbn-lens-embeddable-utils/config_builder/charts/table.test.ts @@ -80,9 +80,6 @@ test('generates metric chart config', async () => { "test": Object {}, }, "datasourceStates": Object { - "formBased": Object { - "layers": Object {}, - }, "textBased": Object { "layers": Object { "layer_0": Object { diff --git a/packages/kbn-lens-embeddable-utils/config_builder/charts/tag_cloud.test.ts b/packages/kbn-lens-embeddable-utils/config_builder/charts/tag_cloud.test.ts index 08885ba57ba83..fe94e8f789d43 100644 --- a/packages/kbn-lens-embeddable-utils/config_builder/charts/tag_cloud.test.ts +++ b/packages/kbn-lens-embeddable-utils/config_builder/charts/tag_cloud.test.ts @@ -80,9 +80,6 @@ test('generates metric chart config', async () => { "test": Object {}, }, "datasourceStates": Object { - "formBased": Object { - "layers": Object {}, - }, "textBased": Object { "layers": Object { "layer_0": Object { diff --git a/packages/kbn-lens-embeddable-utils/config_builder/charts/xy.test.ts b/packages/kbn-lens-embeddable-utils/config_builder/charts/xy.test.ts index d1646b4c0ec7d..42dc00dc2ba26 100644 --- a/packages/kbn-lens-embeddable-utils/config_builder/charts/xy.test.ts +++ b/packages/kbn-lens-embeddable-utils/config_builder/charts/xy.test.ts @@ -87,9 +87,6 @@ test('generates metric chart config', async () => { "test": Object {}, }, "datasourceStates": Object { - "formBased": Object { - "layers": Object {}, - }, "textBased": Object { "layers": Object { "layer_0": Object { diff --git a/packages/kbn-lens-embeddable-utils/config_builder/utils.test.ts b/packages/kbn-lens-embeddable-utils/config_builder/utils.test.ts index 7709c6969b29f..b4b7c7ddc4842 100644 --- a/packages/kbn-lens-embeddable-utils/config_builder/utils.test.ts +++ b/packages/kbn-lens-embeddable-utils/config_builder/utils.test.ts @@ -199,9 +199,6 @@ describe('buildDatasourceStates', () => { ); expect(results).toMatchInlineSnapshot(` Object { - "formBased": Object { - "layers": Object {}, - }, "textBased": Object { "layers": Object { "layer_0": Object { diff --git a/packages/kbn-lens-embeddable-utils/config_builder/utils.ts b/packages/kbn-lens-embeddable-utils/config_builder/utils.ts index 21c48ca76a52b..78434f8dbb10f 100644 --- a/packages/kbn-lens-embeddable-utils/config_builder/utils.ts +++ b/packages/kbn-lens-embeddable-utils/config_builder/utils.ts @@ -191,10 +191,7 @@ export const buildDatasourceStates = async ( getValueColumns: (config: any, i: number) => TextBasedLayerColumn[], dataViewsAPI: DataViewsPublicPluginStart ) => { - const layers: LensAttributes['state']['datasourceStates'] = { - textBased: { layers: {} }, - formBased: { layers: {} }, - }; + let layers: Partial = {}; const mainDataset = config.dataset; const configLayers = 'layers' in config ? config.layers : [config]; @@ -226,7 +223,14 @@ export const buildDatasourceStates = async ( getValueColumns ); if (layerConfig) { - layers[type]!.layers[layerId] = layerConfig; + layers = { + ...layers, + [type]: { + layers: { + [layerId]: layerConfig, + }, + }, + }; } } } diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index d38e1399ed3aa..9c96bfe371dfa 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -86,7 +86,7 @@ pageLoadAssetSize: kibanaUsageCollection: 16463 kibanaUtils: 79713 kubernetesSecurity: 77234 - lens: 41000 + lens: 42000 licenseManagement: 41817 licensing: 29004 links: 44490 diff --git a/src/plugins/event_annotation_listing/public/components/group_editor_flyout/group_preview.test.tsx b/src/plugins/event_annotation_listing/public/components/group_editor_flyout/group_preview.test.tsx index 09c7c5a265355..386976ac571b6 100644 --- a/src/plugins/event_annotation_listing/public/components/group_editor_flyout/group_preview.test.tsx +++ b/src/plugins/event_annotation_listing/public/components/group_editor_flyout/group_preview.test.tsx @@ -237,7 +237,7 @@ describe('group editor preview', () => { const assertTimeField = (fieldName: string, attributes: TypedLensByValueInput['attributes']) => expect( ( - attributes.state.datasourceStates.formBased.layers[DATA_LAYER_ID].columns[ + attributes.state.datasourceStates.formBased?.layers[DATA_LAYER_ID].columns[ DATE_HISTOGRAM_COLUMN_ID ] as FieldBasedIndexPatternColumn ).sourceField diff --git a/src/plugins/event_annotation_listing/public/components/group_editor_flyout/lens_attributes.ts b/src/plugins/event_annotation_listing/public/components/group_editor_flyout/lens_attributes.ts index 7943b1d905b6a..f9e56ded409b9 100644 --- a/src/plugins/event_annotation_listing/public/components/group_editor_flyout/lens_attributes.ts +++ b/src/plugins/event_annotation_listing/public/components/group_editor_flyout/lens_attributes.ts @@ -146,7 +146,7 @@ export const getLensAttributes = (group: EventAnnotationGroupConfig, timeField: export const getCurrentTimeField = (attributes: TypedLensByValueInput['attributes']) => { return ( - attributes.state.datasourceStates.formBased.layers[DATA_LAYER_ID].columns[ + attributes.state.datasourceStates?.formBased?.layers[DATA_LAYER_ID].columns[ DATE_HISTOGRAM_COLUMN_ID ] as FieldBasedIndexPatternColumn ).sourceField; diff --git a/tsconfig.base.json b/tsconfig.base.json index d241aace37840..78c48a4acaff8 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -968,6 +968,8 @@ "@kbn/lens-embeddable-utils/*": ["packages/kbn-lens-embeddable-utils/*"], "@kbn/lens-formula-docs": ["packages/kbn-lens-formula-docs"], "@kbn/lens-formula-docs/*": ["packages/kbn-lens-formula-docs/*"], + "@kbn/lens-inline-editing-example-plugin": ["x-pack/examples/lens_embeddable_inline_editing_example"], + "@kbn/lens-inline-editing-example-plugin/*": ["x-pack/examples/lens_embeddable_inline_editing_example/*"], "@kbn/lens-plugin": ["x-pack/plugins/lens"], "@kbn/lens-plugin/*": ["x-pack/plugins/lens/*"], "@kbn/license-api-guard-plugin": ["x-pack/plugins/license_api_guard"], diff --git a/x-pack/examples/lens_embeddable_inline_editing_example/.eslintrc.json b/x-pack/examples/lens_embeddable_inline_editing_example/.eslintrc.json new file mode 100644 index 0000000000000..2aab6c2d9093b --- /dev/null +++ b/x-pack/examples/lens_embeddable_inline_editing_example/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "rules": { + "@typescript-eslint/consistent-type-definitions": 0 + } +} diff --git a/x-pack/examples/lens_embeddable_inline_editing_example/README.md b/x-pack/examples/lens_embeddable_inline_editing_example/README.md new file mode 100644 index 0000000000000..ae280f9a4c17e --- /dev/null +++ b/x-pack/examples/lens_embeddable_inline_editing_example/README.md @@ -0,0 +1,68 @@ +# Inline editing of Lens embeddable + +To run this example plugin, use the command `yarn start --run-examples`. + +This plugin contains examples on how to integrate the inline editing capabilities to your Lens embeddable. + +Steps: + * Add UIActions on your start dependencies + * On your embeddable use the onLoad callback to store in the local state the adapters and lensEmbeddableOutput$. + +```tsx + // my Lens embeddable + +``` + +```tsx + const [lensLoadEvent, setLensLoadEvent] = useState(null); + // my onLoad callback + const onLoad = useCallback( + ( + isLoading: boolean, + adapters: LensChartLoadEvent['adapters'] | undefined, + lensEmbeddableOutput$?: LensChartLoadEvent['embeddableOutput$'] + ) => { + const adapterTables = adapters?.tables?.tables; + if (adapterTables && !isLoading) { + setLensLoadEvent({ + adapters, + embeddableOutput$: lensEmbeddableOutput$, + }); + } + }, + [] + ); +``` + * Create the triggerOptions. You will need: + - The attributes of the lens embeddable input + - The lensChartEvent that you retrieved from the onLoad callback + - An onUpdate callback to update the embeddable input with the new attributes + - An optional onApply callback if you want to add an action when the Apply button is clicked + - An optional onCancel callback if you want to add an action when the Cancel button is clicked + +```tsx + // my trigger options + const triggerOptions = { + attributes: embeddableInput?.attributes, + lensEvent: lensLoadEvent, + onUpdate: (newAttributes: TypedLensByValueInput['attributes']) => { + // onUpdate I need to update my embeddableInput.attributes + }, + onApply: () => { + // optional callback when Apply button is clicked + }, + onCancel: () => { + // optional callback when Cancel button is clicked + }, + }; +``` + +* Add a button which will open the editing flyout. Execute the IN_APP_EMBEDDABLE_EDIT_TRIGGER trigger onClick +```tsx +uiActions.getTrigger('IN_APP_EMBEDDABLE_EDIT_TRIGGER').exec(triggerOptions); +``` + +### Important note +In case you don't want to open a push flyout you can pass an html element to the triggerOptions, the `container` property. This is going +to render the inline editing component to this container element. In that case you will need an extra handling on your side. +Check the 3rd example for implementation details. \ No newline at end of file diff --git a/x-pack/examples/lens_embeddable_inline_editing_example/kibana.jsonc b/x-pack/examples/lens_embeddable_inline_editing_example/kibana.jsonc new file mode 100644 index 0000000000000..01540fe2de3a1 --- /dev/null +++ b/x-pack/examples/lens_embeddable_inline_editing_example/kibana.jsonc @@ -0,0 +1,21 @@ +{ + "type": "plugin", + "id": "@kbn/lens-inline-editing-example-plugin", + "owner": "@elastic/kibana-visualizations", + "plugin": { + "id": "inlineEditingLensExample", + "server": false, + "browser": true, + "configPath": [ + "lens_embeddable_inline_editing_example" + ], + "requiredPlugins": [ + "uiActions", + "lens", + "dataViews", + "embeddable", + "developerExamples", + "kibanaReact" + ] + } +} diff --git a/x-pack/examples/lens_embeddable_inline_editing_example/public/app.tsx b/x-pack/examples/lens_embeddable_inline_editing_example/public/app.tsx new file mode 100644 index 0000000000000..8ff88af42b520 --- /dev/null +++ b/x-pack/examples/lens_embeddable_inline_editing_example/public/app.tsx @@ -0,0 +1,182 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo, useState } from 'react'; +import ReactDOM from 'react-dom'; +import { css } from '@emotion/react'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiPage, + EuiPageBody, + EuiPageHeader, + EuiPageSection, + EuiPanel, + EuiSpacer, + EuiButton, + EuiTitle, +} from '@elastic/eui'; +import type { CoreStart } from '@kbn/core/public'; +import { LensConfigBuilder } from '@kbn/lens-embeddable-utils/config_builder/config_builder'; +import type { DataView } from '@kbn/data-views-plugin/public'; +import type { LensPublicStart } from '@kbn/lens-plugin/public'; +import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import type { StartDependencies } from './plugin'; +import { LensChart } from './embeddable'; +import { MultiPaneFlyout } from './flyout'; + +export const App = (props: { + core: CoreStart; + plugins: StartDependencies; + defaultDataView: DataView; + stateHelpers: Awaited>; +}) => { + const [container, setContainer] = useState(null); + const [isFlyoutVisible, setIsFlyoutVisible] = useState(false); + const [isInlineEditingVisible, setIsinlineEditingVisible] = useState(false); + const [panelActive, setPanelActive] = useState(null); + + const configBuilder = useMemo( + () => new LensConfigBuilder(props.stateHelpers.formula, props.plugins.dataViews), + [props.plugins.dataViews, props.stateHelpers.formula] + ); + + return ( + + + + + + + + + + + + + + + +

    #3: Embeddable inside a flyout

    +
    + + +

    + In case you do not want to use a push flyout, you can check this example.{' '} +
    + In this example, we have a Lens embeddable inside a flyout and we want to + render the inline editing Component in a second slot of the same flyout. +

    +
    + + + + { + setIsFlyoutVisible(true); + setPanelActive(3); + }} + > + Show flyout + + {isFlyoutVisible ? ( + { + setIsinlineEditingVisible(false); + if (container) { + ReactDOM.unmountComponentAtNode(container); + } + }} + onCancelCb={() => { + setIsinlineEditingVisible(false); + if (container) { + ReactDOM.unmountComponentAtNode(container); + } + }} + isESQL + isActive + /> + ), + }} + inlineEditingContent={{ + visible: isInlineEditingVisible, + }} + setContainer={setContainer} + onClose={() => { + setIsFlyoutVisible(false); + setIsinlineEditingVisible(false); + setPanelActive(null); + if (container) { + ReactDOM.unmountComponentAtNode(container); + } + }} + /> + ) : null} + + +
    +
    +
    +
    +
    +
    +
    + ); +}; diff --git a/x-pack/examples/lens_embeddable_inline_editing_example/public/embeddable.tsx b/x-pack/examples/lens_embeddable_inline_editing_example/public/embeddable.tsx new file mode 100644 index 0000000000000..717a8b2d20f8e --- /dev/null +++ b/x-pack/examples/lens_embeddable_inline_editing_example/public/embeddable.tsx @@ -0,0 +1,161 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState, useRef, useEffect, useCallback, useMemo } from 'react'; +import type { + TypedLensByValueInput, + InlineEditLensEmbeddableContext, +} from '@kbn/lens-plugin/public'; +import type { DataView } from '@kbn/data-views-plugin/public'; +import { css } from '@emotion/react'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiPanel, + EuiButtonIcon, + EuiTitle, +} from '@elastic/eui'; +import { LensConfigBuilder } from '@kbn/lens-embeddable-utils/config_builder/config_builder'; +import type { StartDependencies } from './plugin'; +import { getConfigOptions } from './utils'; + +export const LensChart = (props: { + configBuilder: LensConfigBuilder; + plugins: StartDependencies; + defaultDataView: DataView; + isESQL?: boolean; + container?: HTMLElement | null; + isActive?: boolean; + setPanelActive?: (panelNum: number | null) => void; + setIsinlineEditingVisible?: (flag: boolean) => void; + onApplyCb?: () => void; + onCancelCb?: () => void; +}) => { + const ref = useRef(false); + const [embeddableInput, setEmbeddableInput] = useState( + undefined + ); + const [lensLoadEvent, setLensLoadEvent] = useState< + InlineEditLensEmbeddableContext['lensEvent'] | null + >(null); + + const { config, options } = useMemo(() => { + return getConfigOptions(props.defaultDataView, props.isESQL); + }, [props.defaultDataView, props.isESQL]); + + useEffect(() => { + ref.current = true; + props.configBuilder.build(config, options).then((input) => { + if (ref.current) { + setEmbeddableInput(input as TypedLensByValueInput); + } + }); + return () => { + ref.current = false; + }; + }, [config, props.configBuilder, options, props.plugins.dataViews]); + + const onLoad = useCallback( + ( + isLoading: boolean, + adapters: InlineEditLensEmbeddableContext['lensEvent']['adapters'] | undefined, + lensEmbeddableOutput$?: InlineEditLensEmbeddableContext['lensEvent']['embeddableOutput$'] + ) => { + const adapterTables = adapters?.tables?.tables; + if (adapterTables && !isLoading) { + setLensLoadEvent({ + adapters, + embeddableOutput$: lensEmbeddableOutput$, + }); + } + }, + [] + ); + + const triggerOptions: InlineEditLensEmbeddableContext | undefined = useMemo(() => { + if (lensLoadEvent && embeddableInput?.attributes) { + return { + attributes: embeddableInput?.attributes, + lensEvent: lensLoadEvent, + onUpdate: (newAttributes: TypedLensByValueInput['attributes']) => { + if (embeddableInput) { + const newInput = { + ...embeddableInput, + attributes: newAttributes, + }; + setEmbeddableInput(newInput); + } + }, + onApply: () => { + 'optional onApply callback!'; + props.onApplyCb?.(); + props.setPanelActive?.(null); + }, + onCancel: () => { + 'optional onCancel callback!'; + props.onCancelCb?.(); + props.setPanelActive?.(null); + }, + container: props.container, + }; + } + }, [embeddableInput, lensLoadEvent, props]); + const LensComponent = props.plugins.lens.EmbeddableComponent; + + return ( + + +

    + {props.isESQL + ? '#1: Inline editing of an ES|QL chart.' + : '#2: Inline editing of a dataview chart.'} +

    +
    + + + + { + props?.setPanelActive?.(props.isESQL ? 1 : 2); + if (triggerOptions) { + props.plugins.uiActions + .getTrigger('IN_APP_EMBEDDABLE_EDIT_TRIGGER') + .exec(triggerOptions); + props?.setIsinlineEditingVisible?.(true); + } + }} + /> + + + {embeddableInput && ( + + )} + + +
    + ); +}; diff --git a/x-pack/examples/lens_embeddable_inline_editing_example/public/flyout.tsx b/x-pack/examples/lens_embeddable_inline_editing_example/public/flyout.tsx new file mode 100644 index 0000000000000..f916abbad18f2 --- /dev/null +++ b/x-pack/examples/lens_embeddable_inline_editing_example/public/flyout.tsx @@ -0,0 +1,124 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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, useRef, useState } from 'react'; +import { css } from '@emotion/react'; +import { EuiFlexGroup, EuiFlexItem, EuiFlyout, EuiPanel } from '@elastic/eui'; +import { euiThemeVars } from '@kbn/ui-theme'; + +interface MainContent { + content: JSX.Element; +} + +interface InlineEditingContent { + visible?: boolean; +} + +interface Props { + mainContent: MainContent; + inlineEditingContent: InlineEditingContent; + setContainer?: (element: HTMLDivElement | null) => void; + onClose: () => void; +} + +export function MultiPaneFlyout({ + mainContent, + inlineEditingContent, + onClose, + setContainer, +}: Props) { + const [flexBasisCol1, setFlexBasisCol1] = useState('100%'); + const [flexBasisCol2, setFlexBasisCol2] = useState(!inlineEditingContent?.visible ? '0%' : '30%'); + + useEffect(() => { + setFlexBasisCol1(inlineEditingContent?.visible ? '70%' : '100%'); + setFlexBasisCol2(inlineEditingContent?.visible ? '30%' : '0%'); + }, [inlineEditingContent]); + + return ( + + + + + + + + {inlineEditingContent ? ( + + ) : null} + + + + ); +} + +function InlineEditingContent({ + visible, + setContainer, +}: { + visible?: boolean; + setContainer?: (element: HTMLDivElement | null) => void; +}) { + const containerRef = useRef(null); + const style = css` + padding: 0; + position: relative; + } +`; + + useEffect(() => { + if (containerRef?.current && setContainer) { + setContainer(containerRef.current); + } + }, [setContainer]); + return ( + + + + ); +} + +function MainContent({ content }: { content: JSX.Element }) { + const style = css` + padding-top: 12px; + padding-botton: 12px; + } + `; + + return ( + + {content} + + ); +} diff --git a/x-pack/examples/lens_embeddable_inline_editing_example/public/image.png b/x-pack/examples/lens_embeddable_inline_editing_example/public/image.png new file mode 100644 index 0000000000000000000000000000000000000000..a7b47acc8cac51aaaa6002f6a5e98c27c5008118 GIT binary patch literal 155151 zcmd41bySqW_b|Q|C}+@M&^3LydwdoDHm+x6ZYCK^3%y@c+qk`RxVt*mQ}bhY z?`S6xndaAh=JjfIWAB1X`_As+S$kFe*6hX*>TGgjdFzOYh3l*ZH{HE+cF=G(Ufwc& z*x+fsJD2`v>Iy*gG-Pm2k?{04&Z0;VeZS8N53?3dG6WaF9 z!Lw)2b{3YlxAsm>Px0*y;LO~{_QCS{9)5Fgee2+j1!{0`con~~JvuzUuxx4PxwwoU z8=oE;#*NNyuB@)FtncrPjj9(!4bQA^6QCa+Y%k-trzW@Y8#@!@TN~SZgtmXw)Y8#A zxi+!5y@21_CNyw%aC&`bXyE&=g58<9?X}Gd)dhW{bCtb|+u-!Z#s-0<^D8@(v-pwG ziS42A+*4;Z$UDIR~S~EAl*wNLqw6xSWFdSC{HZ-<;4T~x)shF6U#BHwF zJGv%jmbbNcO-|2_EbQqbjh{;?D643Bczui*X}VyXd=aQS-C51eEAk6K?`ND!oE1Z`@Xk)eyrnb>Ezk$NaXjpxdxL@E?xhagzGE@tBOySJI?+zoK@$me(T*mKAc_L zK=`(w9rf(zyA(zY?yMj0{H|2?#eBpToUCk(r2oJl?_2yBXc=DF%WXW1^T&1!RWuhGZW$#bgY&(WUKtNb70~{3MQiyRH-!) z$maTw$kqPtupARIPp9&h-`YXw7c*K|162*s zPd?F5Uaw!z-+J0pWwi1UA=z}gAtt)UM$i;Ujc-NoxfMckA5Fv0`=L7k^t`wJ3@1PD z1*DeM8AoMj&{^0qrkx2t^-se8~|Gs<@TV|0IM_Yql`kh55V+px| zy-+hDoiqE2VQ5D(yWgRZ2tvT+*s}*S_tgvHJg8Ej8Ah1G8~{Qlu?Xvap*pw`c1Nfv z!T|EFgMd~|h=W?jBg6&gah0sOQvi~SAmFrbOs-dyYyfdKRC9$w#3o7)fr5TZ)I9N{ zbJ%c;j+Yun6wrRvI7m%b(vE$C>u{5@>iIfAh~E>k@=;fY0kY1E=&Z+Zd=VbsZ_9yV zlVqV-mC)a!5|Hoi@7d9ppji;3LB2H>4)2dqi78k=zuqc8KWxe@aYN=EY!X1Fk)gu8 z@#x|^Qe;gx31qi^Ir28TL5ug;B)J*Q05J4M(-@i0Go|-X2&U%B`Q{Xbc=K-wT|XaxZo63e zaMvgR&J_&8W%K#){Dct%f$slIWT`_xEg>}B7$+AxJ98KvJ6bT>m%LkCOQfq6~o=3a<(b>UtGr$JPnwab@4X1O^ z=a>dtP&Wce%vzpL^?$6q>nALr@;r$+(EZXhHU`V&LGlNtZ@3BZTuU}Jbi%+vnp^?{nF$e%BHwzfgEV~KWdvad*57&x0WvAhR({QE1K4f*C zxS9`u42Z#s#6_&DTiVJs0V>~8fQfM#7Z;ydplz?SwI5jAW*yw=AO0Tz>;b=0qt6P^ z*Ce02*GG^LXV7z7PcIaHQ{6&*3kJt2Kup*)9PjE=rBj;Bxjp5kdl5o|fuJ=ZE8lJ$ zH^_!+vRTkt&QuA1kuP8l6@QM+Xap!`r!js!M`}E1;k#&!6KYs{02t9#ubFKTLlDyn z_R?Bi81A`8u4<%BeJ3WuZg`w41mNQ1Em zZBT)xEV2bBE5b;v7v5Zf&_#A?*84~;3XRau$Y$MsZ4VdX%xbXf4+W6WF>Zg5yjTZD z3~_gQPgm7Kw3p1O;_N-{)xRoMl{zR^>6!iqm2lGFc^X#jsl7%}LV+A3J4@&J5~sqr zlFj^MN%D|c5OZr5NSemHynRP%t=fx>7eS!r0Rf+vOBV%QMXF!?YUGtFTF&7*3OPC} zee3Ws#;vkktQNHU8j2O=ByDL4byOxff^)thZF~o7eZ+NkuEo=j?%U(n4B+;YfBW8Zv-Zeu8dP* zYoiGYl6ytv8+y8g59fgBWMImOeC?AgU8(`~5sra|1Z#QfJk3~IDNMhQKEl@YZiZ!W zp+RX2&(uvO8Sd{Y${HUdHUy6qG|sohR@a^_rT6kj-6u0 zpf%R3^RosSfK2^m&fGhxE*-X#h3`1t;9*Hl((O2hVd89 zhm`M?cwTt+XtWVhB!L1=qWKAIhh~Nj-fu0%6+q^tNUd^y2AO*?)0>!&3tJ2fqU~K^ zXn=8bB7K}1Owd`Tl$FgNWL7NZD+q>@zq4Tr1YdU{#!ri*(O@?571JHJJ&(uL&xNZy zl{OdYd(z<9gD|Db-E^plI~8{{buS;jX%bM>3N&j)&96K8ZMa z-jb@`W0N@x{1p~J@=-G?@ixR-T!^(KkfrNOSY1-m?37CAteml%KkH$Zcf6Z++Ogn~ z%e9cUMu60oUh4t+i03Bu_BSj{GC|CgK5*XQg+b6X5$N4(>_U|(RwWT@6Djthm#^iF zEx4#?;5O?6NoZse5WM@? zZ^@QHv-LrGM%|TR)9gr^lPe`YPP_Mw$~z1Yr1`qT^|`K$@=f`^sL}f)mfH;RJ}Ict z)m#+!Qr&+-oei0_o&}g3XG(2Z0%YNhptPWyxQmLk~!&V*4=+-_@qKI z6&*9KI5bEay)ePjEp{~D$5LG-ZCAY)86iXnVAKt+S4R5~TXqk8!>2JSR>NcSM7=^B zqkrnHr*}1>CF^s*8nsJ(!Ub<$_Xpgbn|D`Z zkl!h?3U9cO%PZFiw2V>)cLjq>CHKFRJW+p9D`60hQzzHEZ%EsfDC!fK|M=yW^9?S2 zKTbX4PZpk!ZR^@U%$*GjyK9z&^Pwjspvj}JG8_*f%wzF$c68?V?P8v#|9B7=v>MUh z!aTgu$nklm31xF#G}vfLJ=^3%kVk-eN-4uV()-5s4`=eD1udkb^O{6$oj1?MB8S}W zb}Z~S_i%UdDo2waM5xiL3?w5fj5oXZLcf|8T6>GA#88B zbU&_l!LS9|4vES?>*vL77js#Zp9^ux=-~5a*i)fJ+O^xhr3En%C=2OkSE_QnOjoPk zwxR#GRh66yo%k#IS%hToo%^%7@Z!43)X|>Ro@9@3Np}o}wXDKk3hP-Fit|M?7Ndn( zW-ig#pJmwKWX(YO3WvBmuSxUS>if(`Gat>yrZoQqulHV~BV?A7MsLI>g{qPlc4Z$k zTL?vUP#0{9!P=7@W8XZDf8kd=8PCQwkwYiMl_-xO9(lp+mYx1RhcvBNmo&LfZ$m&U zb1Wf#{Aqju5x3*+yslI>nNttD25okF=17jJJd1tr+`Z#)4H@3MZZw=e3Zx98CDsp` zY?EiFRka%o(kY~p96`G5v9ZgO@TjjcDvrB+LL#$I05%#=jd4zMaV>TNwUhLJgt7to zR7spy81}CF!=r1JtU@k}@Zfr^zH?zoBKj!!=`qipr><((5N%B&Z=XG#LIsy7@UI4< zDQg{rIZI036n~mLPpSH!7TI((GSMkL`HTBJ#>ttc{n{P=wZED5 zG@jTtO0V?lJ|6hc(SnJ7g*w>>4%DmDe(gzb);!Nzw(r0B`nO;DkYG_N!v9@sIwhj> z&(zir!6!oWWP$^9nH|P9+sXKfoFp-JbD}gSxn(gln#Q_nu+9n~o$ahv;Eg=LF%-a#8{e zI|jHTu0umpPdOOYF*q^cY%QO48tOkU zi(rUvJvf`dP=wz^9d*D`s6wMd&~ma5&&t@~s+};{Jol{Kc)w8!+GM7v7|0=`OYw=d z0g)}~)w37#@#tLXbsR!RMOi4=B`Q6)Z0&vppU43TM-SKTT&_Te0OEjv%psTreptJPD_}07|U)u zU;rEZeH$iI>Mx8yG89{#Bl4#e-PJYICCpDv z>&zaY(4fef<0TbXrg*f^2xbA3NTDa*j<_!}zZ);=7(CF%>NG03mtUVq0Y4kRxTdoV zPmFmYT0iL@6`JCxq%?1C?%*cZkTaB7p@Y9-_}AA8`z_r{@5|#`Y-R&gBOm@K3dtDo zDee)lWhhz1gy^q2EyMA>oo7e!aBG~=Go^7I0W_x5G)U7CshackzI}gZ|2Rui$i?n+ zg+X5)yo7QUtZmO3&gRa348y`g5A`rftBL6z^16#~v+Oy04J&bh^h$MM_-73bO6mHk z7u(9NSw2*{*$eP=_aC~Q$*xqTPB>iJZAYEHIuVyxm;LbtcybphHzX#SuDJYK4Zy<` zlPVK0onkJv&Hcd3>{PlrXX>9L#ed!9$Xh{gzOhb_BY*wDY86xmr@EaJ^t*u#b6LGM zPrT(?%8zUZqyTFDQ$>~yPB?{x)E`aR$!WYa%#>$Fml#k<_v^gw043`rMn(*|&kB z@E2$wCmWr#D7~Nc>XGnRv@l9HDmUKgPpN<#?;Z{~ojP)aGWgzc`Z?E^;e^bHv3AaD z^1BOV`1X|U>|=%hsnV&4CmR9CStZY3eSUs$_^XvtM_lJvKR;yS=1nJAkw>(kH(N&G z^G&O+B#_VBGHb=DXisgj#cmW+d+)xvZO*t&9w32zVxA$C987Z8JT|QuudZUBc`6Rq z`*2=svD1D_Z`Zb#QI;!I`L#7&g4>4ckWodd|2jpYMOkeAX=`d`baGg?N6{k}Rw(H{ z{h}q;c#yAv^MX-5LhF|V_9A?Wv*w+7?1Vo)g)FNPB>0C9gN zb7=9O=jE^X@J{Z>O!(#RaxqVTx?jPzyeV%jSJ{c^v#rBa*fV9gIU&s-`aOfuJZ!K5 ziKb(pdhG8mEoI4kdXjU$_lXUe-&_x1nQ^${`U|}CkBxPE@7lCOV{@0-QOhn`MvlmD zw(6XJnr1A9^SR{G9dUAzWM*Hj#Gmxp`aO`yLij*4($TGu;wUffEm^&8;K3`!^l}T0 zyh4UjqMO$yq!TrNSr>sl1iuQa(!$=YU(lf|F4OrfT}lE$`(a8vHY_{MwlWg@>got_ zFB108Q@|3gobZu$deZDlVHtu z)X>uGka^X@ltEiaE$P$e5JS2FNzm}?Y4^z)yVbfi1)3=g-ayesHFX40elTjm~>RPaQb9hx|1Juc*$?G8XT0PP)&WxN?Wi zDk~}{wX87SKB(}h&bn?9v3!>=-&JfvC`LM-=D~vw@)tpgnG;=oZTh|pGWnwERyq7J z1!dft_cbzNDlaCOt&8L`&8$TK^Ax+lRILM(D;ii4XRHAoLZfGtY%Vl z8&;>&QP~o@1VMg2p5n?pR9wbzA}Rvz-fV{3mqu7-c9OhSh-{m*dQ(ct8@XIyyJA%I zn(UX<15rhI080Qq5UgB1wpnAMY3lTf~x6$>7M8tr}+u`y&^?oDRp7$<3IVqSA zGKulKH@+g%Onm2<$bh+$`)#Z{*N1!bro%TcN11Z(TG9@2K2ZPQH?0wI!t520`=PmP zb*?eevcLU#n0e3PkvI_jo#insxjn%=-gOSuU(SL!-ddACV%BprJ>DFPEw(;33R>x2 zqY4p=5PLFN{}m-#2sb=?MW{5!F;=gwl^A##llNIUEf>{ViRoQfFS|X=N~Jg@&}&i3 zss?h&k!c8EMMOmK;K@e~LysD%Qw4N+RIfn%Vewna?)=e-mV^wz(64N|_C*o)rZW0c z%@wY91-Bs{C8v(m=#20#pvZbLl7$(|N#>4=2?Qe~+QxkIIm&=nyrT$RT>~Ebw{lS|MH=JR;p7_?& zHn|4)d0BSS`U*rWf5vA%Bc3J6?@5dtJ|wi7|P>@JuS3ab1D7~>*_#|qET zbXkKDhU7uGer#6~>gAR5QYK-O^{~{zFqV%mk+h$!SF#*CkmnsBy47f`d5<;SJ2d-xi(snM&Xy;O1 zFnTS-W%r&zVkD0O@*~r&(ja4}DZ*W5XY#@f9P&Nxf#S+#qf>6S(863A$UOzy?^A9c z&t&Sw*a$`YmBQYLI7oZ7=14Imu3U0-Mf87pyI? zD=-KZI!F6c1~WD;o{vT7+Esh2jNl>7D~R*q4;rDMD4+bnOXrG`V73aU?eoDKsew?J zA&$jd+}oI7OKTyI^TDfX;^?D499ezGn3CZ1?+gUL3VHT@AAv8t`=j9yunJz%7CXO< zdUtQb0Vn$cEgbc9+|mbu>c4RLe5U^bg6oYvGGGzVP(t&H{GIu@+W}{+jgHyo^9%2g zbBIm(i_(n;ZfIfhHUJyeG@8MOT}6B#tcP5^A%fNSoyD|WtLH?iM}q=T@$=!!{_$Y+ zd*OBZ%R^WGf>Z(k=|f$C!iO{WN{*3Adx*<83!xbTGZd;>b7C1Xru6g+0Z*u(CQr>q{Oj| z6Ksmm_E8Ss!05r{Q0{$PPE~c+ld=(vrA8y3B-yF{ISj=e+)B!6xkL z=p*Ag1Zqm3N{YKodD|YjeblnsDM3|4-@m+C?h|$xHpW*2D@pL!SnxVx9ifkH`76fH zHZxEfvL{Qf*{y&%jmKMD?v{QyIBjF+KBnw-lrN0mcb&gQA-r?ADz*z!e07IOarZ)L z2FtN3n~5j9|0Iw%wg4SGD(XEQ1CCmz%30k8VPm!oD@h2hgFhG_R-rrp-7D)Q0@YKU zNh`G>MMqBLf=#-Ozqe{1GO>z(c=nDDTNFBMe3)|he~}au?T8-DS(8y&KB&QCv|6TC zXIe9a7nA68X=X8}QGai0YlZ?HANh4rFer(9H$@+LmY=@iPD6Q?gYnE*?$8Mnn2YH@9bIZF152742eq;$s*PN5 zH41;-laX~}3y_f9c`~vzV~_M`@m+A5z++|{rlu8KdX9dk(5#^8zW;}vSvL^)m6a7g zc$4Qz3qaWnY?!I;(I-s6Xrz=4p~ayayTH+;>HPXHdBpYhe|FWR=?@)z;v^m%^9=2d z3;Z>_?;wY79^jf11Y zAzTM(^RaSG+V6?$s*J66(DHdkd2FMU*f3-r7uK(|BPr_`k zp#$2|IgGE?4FU|vT>|Km(^ggRl-8?C7tNnNcjd3!qn>iW`30cRZ7%My9e=gg^p+@g z%#GJA*qyiafZ8Dg2r>{mhhQ4|98Gs(NiLHZXIt;|H{@aHH=BV(e26>m(gF2q@OgZi z)NOu<9Xotnw*x)(5<5JgoywVixmEfPvS#bz+KJuvE;#!L4~{184R;O>y~!q)2bMd? zp8WM~XFq4E&o_feeErLkdw2et1LVX1o1c#~&Sm-T**~Sbnp`-HMClnCR-YFHeb)6x zdEdn(9T2X-Y*4812m!02*9D~&IHXtcb;AEk_0CeVi0s0wnTv~y2juo5@VL@mQU8P; z1_B?SU1&g{NGIopUQ{&>Xvzl#?cq5e;t8vs-Ha`^`CW`7wCoMeB5LofM$J(RKpgELs|FkJC1z0)VN8(5J6xP*M!&|p7~_YfS&n?PNsEhev+|(??B3xt zMm0kPb27$qxI>`A&MW)6P?xo;Z7aptZ^etP z{;h{xD$()yzp`TC=F;a`-4SM`%9Ld-3>h81GSbG~nRi0H9+MhzQvI+D}r=j>rfWEeLK3 zSN?tu*IIO6Ev*!e^%N5mdpX1Qe?yJV*36hCstNu>2DEfyiWB4~T-;(g?Fj@>)hqYg zmkN>E@wW3%_XhwDVpv2r%?#gp77+MDH#W(>R-V)WfoP)%D&ypfV=B-bH^jQ!_lY1Y774VPBpUbQ`v7N?bx<03)+ zy!SB%b47|Im_2=)>f6(cA)%+}_md_^P-_!&;-gc;Kt=y2^Fs>G`}1%(XSQ2e3qbWZ zAE_Ci!Auac&UeQ}nBMfQ1c^NDO_2Dn%}$!zd$~Y!#xBgfmWqv;PS1d9efzfv;zc|E zs-F!qQ@eO*vQruZvYt~6c~_}&tk_%FA+IgEKlw3)!yBWMy`%%vVro5CbjWVgW)@Ui z?b1E&3^2VqsAT_Nq=XQ%4+l-`g=eDw%oK9u3njkSg+QMlZVAtUxHHk0zL*gETogYy za>C<;W&mPO2a-o1vY&+!I0k{NP!N_kTLkE_UEcV}a6YoGMu0WLRYxeZoVS%oGqf;) zwbLn2Pl3HTBcXh*-Vyy?KBemg;V0lNs|Te~{Df)uq|lcLNqdidUw`DvyyLE*!K#w2 z`AJPf^b6E$GQtFcr~Lv#&1lXjzrez$-Ngp-ju3;obL5Pi({uo>{3F5>Op=T2I}{Cn8hcE3g~mRe6Q5fM1t^JL|BX-*IYl;#~Yl3Ej+6b62h zS!JQ2M+>`Yy=vW(CpBnxO?Uv z!&BLzP%YM{yK$t3evKR=QNLNVd2VW;+vYOQ)z}`19%$0Ha%dbC_%=7fzYG#aXbI~z z(d^Wuv*W0{ve6((wWgbn9wW0@ZEZlR1Csi`8z+|inafGH_4;l_>g5e3Pg05K1+2i=b0gLTqDsB3P(}hvp&1}S`satW$uk5N z;mw=y<>q*{%-Hcb#<1PiYHsd`AzUl};tPH(OrPJRuzc%KV__h2$H2@lVI+^p-aw4h zKtM+*V}gi5Clr*U$uB4V7Nd2Oi=BhikLmY-dUS{H@0TKv&@v~#sQ9trIZLx~_Q;A} zhA9q#n8-##7MsK(ob=utxtyu`wj>4lnKD)t9rSqF{*#zL0VN0m6$U!;)b&V|J6G?| z)?5STN*EHXkyfPWTkBN_{BDv!ZseKLAHk8zni4~4+juRTl+lFD@!R&9+OM6rUZFKd zWAErMms0Hz@9w_;*3t1Sx^s|bz!LOY6=!9CZnD#vptjYv3w1G%$lJ=y9sU{PNW6ltgOpqjU2?prIvBK*9ClcxTaNz>iGwjhu^5UD6{|8M*yzG3WS* z>O3ZX-^lq$Lf}Ut_PvW_(eq*5vT23b^_Gre=-^V|kvlE|MEj{t0Ga(IvzVXeOMWU2 z$c04;Zg<8mPQ@;&;FvGadC_v_+ThscH;SLeb`s1?%AoEP;Wkq3D&5QstCx?MRR@w* z3SY0%ed`tR5xco}yh=epe+F)kD{chFi)?G5G((r4MI*BNDVRSl#tC7APh4wDPSbks zHa}?ChaWt9iog$)9Po&Z9WsTyQ%!yz2Atvu@rHbwno} zwcv18N-J>tjI}JB6~R@v7!n0mDSYr_6h{khQT(~iaXX{%p-gLFt_0Wg3}gHxp969~ z^U}w|jhQ@xzd!dfU%_9gokgnJXm*P&H8j<_5(4k~AehKR3eB!tYeOMo@tZy8#^EH- z#R?FZ*KYq|l`F zE{Qke!C$ebZxPv)I6Yx;bOy0<+7!E5@YmyOG>2ZWn=A}Fms7rjb>^Hfstk~T&@(h6 zR%%l=hT+pJ=40t@0OOSkd9)f6OG<|NZv!togW%}QUY)0Yf$omMck;Ra3 zFx%AKeH?++FlA}o{G1}H0ZTigia&ayWaoz9@)+n5clyhsW-IhjxebNyQ6%VlVsW&V zP?0i*A6_@~XKMpUv&0=Pj6cNcw7zAoI&|rMzkN~8bMjPzU#;?aWrX8BiL112_9I~{ zcwY`|i{B#yP2IbxGLEchr0%Nq^WwogM_YYaG`p><#LZEhS=1MmT_UAGnJ#E0A-mj1wai1K2*iu}nv=P3JB&T&D5EM$*5W)QDL@5-c z8tf%mgN%;n$9;FDuXkRW!({wXO!%d)IQH4GuYyH78hj9c3P+%B^^{D{!4FP}@NWV~ zJJVHUk8vTuhu${eX8}0_)!(y3R5NhemO)=RL0?&vJUe?|e?B?AzM$Lt#CzUg{4jDo z8s*5`0ZjPFta;JM^aXEQ9`DT-_g>DKXBa1?`0+SAbI{(Q8XGT)?ib~_6~ zh;zYVHrxxVqef^ovyc+bN_O(g=gO5*&;{7lpV_wp-P z7Grx_dQ80i2f7zIADAes9}1$Z*K!uoaUi*GTU$*}Gw@`O3Hk|!eLSdiX)s+#rL*8E zUj0appgi}nu3nqL2Cpfew?*hL-8r51*5_uMj?mn~awaJm7QeJ9dA||?9=1YVUhV6( zjdruS3;jB9^gc6f9p~U%@1#C?pFi;QXrj*HvC1rl1}HE-!Qd>FnZ7>y4ib4bma{h7 zBl~(2B+#Q3iPCa}IHIi=f99=Q?>F4`LX*qIv$YXXTNME19&8CZLh`76FS;wr`d78` zzksLM@q=aNP;2AZt9xWOE=xYW5J6=7NnFApYeb7Wh}k~B`F%b6FzxS~p%;wxu4bGu zIg&_x_??JuzIOHG>K1F5;X-=0sD^&O<0bkmnR&X^_B(?8Dd~424iALq`9jM;=h~A?Bof(I~8`z&O z8Qz1s>m32f`~ote^P59&L>L5#!=gCIb`({ss;yUShNAdxoUZo7Ia|i1`4_GLNj>01 zPqiEnD_Ge|6%-f#jkb1LUz4REBUsB?M@87^E9g2fCh%u-=u0mx7pqHmyQ$nInLyCe zNZpV5k3ng7IVl`9z;4bHe&6r)fTeH5+oRrT_*$vmPH}D$)8Y-Nd9`D_FS~M}_SBh) zjAJ5Ac46AGICm)@9W?Ihp7Pg`=}vTlQvhk}`p2ca{@_biDiR-wpDz}6}7R{+~jPM3TVv)eApynYSu?ckl5jfA6y zgW8IVrTGvB>lV9MI`|HCK8g}zF`W4WNtVknqTt*vQ?4lSe?T_`uu>KIjuu5*An%4szGMLcp?P9-4UV!dNO8?0pCRHrI z*Xd_r;!YYGW*G=a(_Yo|R9x<*0G)MRVpE-eWuWMIpe4%vmMafF$&ZX5S$_bz5Drj9 z)!7(?Q9c{V&V4-m%NJL&7d|%uW7qsoh)!|oCj&uz{Xlq^yP?8!hT$Oa;(K_f)oZ5D z=;5^=t1C($z>3E~z?}}wD_qq(u6J&-4(~uKgF8uDZ`)kU8h$opU*8n_!VWh%JV4ev zTbBCTaUDo^*?J2>%?FrhTEDAFK=+ty%dAycHgO{oj$0HS=j4Y? zV}^7_uYHh!`Vqu^F7?Cfa3z(rED^yHY;re$D$E?k->u8MVe&Tl09p&&)QgikRpPj# zLys+Lfft4?fA@G+O%MdAS$>tHE?2j_I>yAN?C9fuD=pm^j$Adt=Bjn#g|$N5NqDil zr+wzCjE5Cp&L$ikJY(2y`jTY=H$-o|bm)*U4&%7!FJ8{EusjBKvLCoT!ymu4U9%YR zgu|-B>lp#8jerxE-fca^k8{&%3S{b0x=aFr&iiWq%D*d{aQRNd@+TTik08~Jm6hga zWv)?9q?iv?-#!v|Rladod9DI_Q@51qKWZIQl=?`^_s)m16Dj+qgOz(PE-G{c@Upi~ z?z1kc@j;my`sRN_8pkQzK3AeeI~<&G_Ic4I0LRAoF!DJdUrQRMXMKc;L z1F5Sff5z*2ll0B%={yBrFkjj_h&UpR2A4v1+)g%tBjG~qN%)a(`xPG{1o~3$jPFsC zZsyrs%T(jji=IMAixT@fm&Jznj!9d(axhiR!a!I9pfxE_e>IsmQL5ELhBN|D=llnxx6R(Pl!)C%e{6f~Kc|!22pDie$p-+&p~AH9 zVn*6?D(BwBLjp=8ww%Evejok(pFT-=53IbW(rIyoPQ$s9T2(-d)tyf&W^i;IMdjL* zW7VA3Gib`N@V%1ZH@dJP&}*jZfrI!@B{cZ?1t-rhUj2sW@yFi`{ndHdNh`0+fpQ=I z(QTc0j~#cGK#&Jm?i)QVsQ!)k$JdDF7!nfG+ka@4Q5|jH#xBG0$wu=afFw3Jy|u_m z`(L6RghO`66@x&ID`reS(@puUz;P2srgEmodi@%JJkBg4{MXY{Nk{AV#wZuCKzgfBZ_GX7lo*=jMWo(fi=d15lMe&!R zG?w!h%C9_9ZmYVCEk$OtCFvR{tioH1olU-ed_ni)vAw9s@y`gMW=^pahchCri zcpbt%JI?*J^v6pUEMVZ3BmI?q3KH&FDSFrL4riyycoHRXPdM{p3lK{g1isb2|9Xsk zmsk>YMWNmhb2BL7g;n-udbBnAA~u{9J=JPU-v~&IUJ=ac+=@#YJ5`6HGm6Y%!JuYf zc(gxVO5f-c?oui`4>>4}@ba{zl<|}s&fElMrw&zGhyoSz3IHq84xyU!dyqz%bJz-*KH}Igq7M3 zqjRIoS<02XDI*961)BRF$sr5vt62qOHS{vRf~b<(8=1?lQa86N+< z?IRI)6&uI$?5^~6^GRtV?V6WlNfc;`8AmwYmg|F0jRMKF2fEiTOHCT{ejRY!Vyhoe z4FsdR#tjp2#m;scgj8v82=xd#jKoO3jJ>Yov#CUTw>`> z?TLP@-h-x$)qfB((5eCU#H%cRL_)L(wyqKxlWh@snsRV)yYN7~l>KG3(j2-Rb5CE3 z4ulX%j{%Z1ef(B`uB&pE9|b#F{_&Bz8b93X7t-;@fb;Hn!V&+YGAbf%688*Il3x^O z?Uj)?{>j;!<=L&*me9e%ZyyoiCYNMCg41CdZEQ6&=4XnOk~3F-OHLXWzpx@<M07bKo4=Y68fc5R?!N^fwS`eM%MIO}ZnWR! z#sFb{PewvDqH>vAGt>8LD@^Mu&zp~}t_F`Qlm!Cb+x`%DhuXwMj}66s7y%~!5L}7p zWi*|~RdgFJ)iqWF!SkiJ6qIYdYU!?XhjlF}nIHYaiaNbeWQ`7N(DKAkcdG;;4GtB0q8)J0lV} ziu3#A%8%mcTiEXT&jAb_zMXtoS5!>~MZ$%Z+-K2kaxTblq_bkR$0Y4h8Vk)!?y}2qGfnO4=0i=$eK_lO8wg~RiOk-{{XZ-q) z7`$kpG}})qn?nt+yQxe>$3w9qz{ktz;#HdGk7ml zB|iBb0B~`p z7o^p|TupMygPwk`OHg799kz249trFZPGKGu+dun{DxGk_mFA=h-r07@eFWcS?_@!< zZ|J?p0y8N%(!jiAx`>MOY?us6eeH;0jgEHBqMT#MX%{$-C#sm98=}yKWs_*e3ZtU^ z?(@AdTaVg$g)IeNjA-7rGL(e z!?_$H(m1SjdeZfT*}n8X%s5S`+}cxwT7Z}!%8lF2kB~`aJYOZotwJ-$SyL!W0Cmo%8HDsvZFF%0U!1xDdr=N}=jaFYUac|-^3HccIFsCXZ>)z=T z-jI%IimvwO!qKMWR6jeRDnXi{Q2##T^Ml-)0i?x6Gbyfj)C=&q;;855rs{9z8<#Ne zUkVmodCtOcn$-^o-A_*brLxt< zYYD@pBeN~aHF{$?O>_O;j#=FMdB5K0z4_n=sxl{ZY-{FzvcPpLDW{>Br~>AW!TK?e z2>HY0E|dpMo47-c!orZxKVj`JB}q+NkuLNERle8L|HQ zwi3GzEX9-hI+fm#Q>@^zUIzH$$?V+HN9*~m%ll)F(BV`o`!-@Sp}&_K5DyL*woQuH z#C^`+5y$Zyd&P$|ouvWS#gzqqV6;rA$}pr>arTX_a*n0-w($PJ)BCy9LQg64v_02! zC10gC_u|L9!-dkVBS2Po_f{glu)gl*?`cM&`?xJzF`?s<$CX^qv1w;dBkOm-H>YY` zVrQ4eF4l}L!0UcOD}2y;D$6gWQTZy*17k9mz9Q5rXQ1l8>g)T6^esR1k17ldy#1hF zZ1wuBf6_8F4YH)M8~9!Ob3ncP#`QRl{Sqzg*fsgK*Y`#bo?h@0gvl7>nAppc{+F=F zFd9=V84IP$Nlte9&JH(TFl%QJrHjpq=ONnJl9s?mb&KO3hbZbPj4%r4+KdxkCig!l zo>!N}QWvvYzl^j-vAe0NrL`AY6b|VLQrXm+YTNP@@ylU7h1B{@w7vCr;9*;asS=xN;7dytpE5y_pg>!D6JBGzto_O#&4(wQuKuRAwRC zuJPQ8zv)zw&d_j$*~bzJ+S~VQy`J)n*fzXabI;6LB(;xDZy#11*k;|ntd2$tGtFHX zY~B{qf9$w9HDLhL3fP0K%r5>{s!9_?9`xymL!k?FUxM+^6{S z?r>e=cM)Da3Fbl^K+Komirg=-t6y3|P8NtJawPsfTY$U^Nd`OL3ZdV=*t`qVqE+!y z{0+(ll-brxt75~IZpB>3aQ<>a?lY~&b)w}{E5kE`suTQr4XY1sg=>gCbVBwhX;OZ? zq3n=EuXgONA&pI2%IPv}n@yP)^NvkjY6%fbNNAnS>8h3}f~-3Wp}#%+En>yXC8LR5 z-3$`YzMG_xM5l@~?T_rrec9XBOi{9f>tlaEXcU?*J##;?K+F=V=b+^I+s`uDwYhUP zYx7om>LK}4*nCN8_JYd7pWpS>jY4S5v{%{&nVn6dJeSNnUc%$tdoUTTaaguYu`~_j z{om&)5D0@f7AOGw7Tl|B@`eHPWo(FXI$F(QShG?kY6ZUYM(!xj!r2)|W`TckTROIb zVslq_D%5dH1v8`fEnl$EXBfyt3sdMVD*igx<9mV6ZiH}ujAu&&BNpwH%|4{ei}+JR z1O|aKTIdI-GuijH(ueIvZM>~Zm@Zs+u`WHM->qhW-!(1i(E}7jQy$Mw0`tbdz2MuN zF66CqIM7lEslS_h_yQcET@oZ?Uzm$aNixIU4AW?NRE>nu%wjuI&-}?hkt+%v>t%vU zEw>MTsjZC$sFvnb&um`)?jEzR&@Q-EB%#mmSFqeF?o#~c$9YAZ@Cpmt3upwl+)?XS zb=WDMPydM)rj_wlr*jZ9s0vO2EBc?HtD=_w4`uHG*3|R#k0J`#XeuC(h$2XDq7Xt8 z>0NpU0qHgLj)-&#B1$jPdvBqO0uhkVdqN966ane&9`O4s@B6?1`#kr+L&!O^v%9mi zb9Q$=JIjS?QBRu9`3zSZ=Cc1Sv|Rjv@^rzRDIdzod`zSHiMc0ZJTrUIt3_GUp~>pU zp4RXoDyJV-Unrd=ejHJ$8HK49`4IKF57zyxac4OF)VdO!!ujA@1~J!T<5G(rrFU<> z*}q{LHE_83>E1b_-uFnC)8Dtg>FDa9`W0pgBkS`88{< z6!@l(3Y4fHO@4gon!Ffk0j^X&2i+-YljL~zig+!~7)IHe86{ALi5BiVs4-VcYl5yo zPUpGAI&-*2>I|Oib&tR%`X1Er6`K{9gggPCag4x*>irYzXo?3{UUlF3ww=;T{(8gi zW$=&MMbtsnvSBV}?owuWwsml(e5-@`N>Bx>L(Qwhv`w@*E7F!N4l=!%-54i4SP+xU64ECnN#+u`Ha>r zj%3Ti%FRZbH2Y+Xc(&E>L5mwnYQ-d;E1KI-RJKMR+EsBi6ujQa9Xv^ zbH1vMs>PdZLi!dF(S0LBjlUGNp!Ojk$?0dhJ^2aRrZ2u?A?Pr0qRT<84w8{@7^mmE zni9}F&KSq^t#MLf^A>%DN-5i|{FMc6|6=HAIlUTgB zX<1lE$y<~1I4vaj&Hdbx8E4&!NA2dw@&g$4aKxWfZK3rzW1G*>$#6B@gh^Q(gsDAU zHpD;4Re$6@qRTu^KNZi};cg5ame|{u_@80HSFB-xHehMKHLO4u(8`mniAzky*w0F< zR><$9)^!)g&h?|o5Bvv%H1h^hOXTy793Hrq-AcZcpYil1aBQwTSaZN7+4i7T7n!Y$ zUQ4t0=v=tLz0b#U?TLG(Ar5Wm&3Ca&1i0S91A(q?+W^lTm67Mx*v28$1)dg#iRNe1 z02W3gaI#rAfWWwlsP5W>(HFXCr`vHtSF7&xi1huu^P&jOi(HY46m@Z$owf(NC(?5r zv$zIj3vz*9pV@u7{p;&T!_A#fdpRWkGp{DN+6VEl`8*KRURkKt;Xq(LQ#a>PyQ1bo zXH8ZEIf_HL@z(^Z5ayb^{jIaAKJ_USo^)I_rZ^1a5Y=Ga3Q^)bnFOS9ezV=`{Kfd6 zPu+Kc>;@DFb5vzYUE}WB|I=o8;EPe#0UlH-Kl1R#>xQmEm*fgwas~V^lBgWl*Jlo%}jW!`xMfCg-66qZ(2+ z$iLe)Im7)RF4^^~tq&m8vKhXWqsAl$tRb60{a)Lg?!QcD9}IYFz9mh^-t+y=nZ@VG z!v94Y$s%X=y%S0^$}3t_N&DSZu72%}hLdbfoL1Cl#x3(?N(~TSQgQDV$knSkOC!DQ z=T)<}mi>H<>K;%fl?NeVTgOFjmLUtyU#2qiWtJfczgu*XE1Q|vd)Zd7KMravGZ(^W zwaXY<8R>~wtyZng%)Bk=9bR$u--v(VZ2Vr&j_XopFbz-p_eESiQ8L`Us#61sN!Af`*HA~H-WVH zi#f!);Y0vui8OD6_4wj)y?f%wZxq^P(cWAswq$eE2!)G}vF|ARGf`ryw`c3ZiNVzi zxw#&(^AS=$k=!^dewgoBW69R4M2MB!YwGHvc3lO-_Ug=tGQlzw=Lq4 zbo|}>!3TJcSQ*~SHdxiL1SBYG87xo=yes8ix^FS}b`6@3>9RWcT)&G|*Qw1};fx204z%7S)BpOstSj*SpU=Mq zzaSqkzk2Db`&WYh3n7r;lJEbW|F?*4*aZqFHSRy8kRkx(_4Y>rknR6VS(FzcZ(|!d zftL8&L;$Jg0zwN9_H-U#1R%ODu{4*h_aBnKq5-~Nis%xzb&0YC#B)jhe0yBPU!+%$z_Ek-}|=@?s&f02s&5 z>>xeEhxn2lKg|ef$$sc}&qH3o8=RlrG*(?Z$1iKzi;%sZnHkc$=jBzYWiCtf+M7{F zAjPbdj&Sm;P1zNmU)38Ir9vruQRIPiiDBVv-<(J09>$a*w_BSeyVjO{8MGqG^aEhOkm*pR)Lh zU#K6CJd>>`0a);k)&mIdDj{U#k2b;wp&bk#VzPe9^Vh$4*3}54KUhozo(dqpJo0b= zkwu-7bv^5CGQ1HA_&%-7%dWtBssZ%2ZVL9v1Nc>XZz21E{o6Ol#!VS~1BpZJN;+XL zlAQISBtaNKvS|7b5kk&!w>s! zcRhk+U%0!R`RiV&Z#M#hf%QBG`lCDimJ^6f=kl)socEsumumP|JOB0Xzdrw}-lcy2 z?^_Q6FZ=&Y1Q1_R{#T-Z-RjHQo;G$!kh|zlf3?U`ci8*=WmmpT)8`Xe7@N(1sbH7d z_Z9ZTaQ8p-lOHN8OH1EsHgwznyEMs{N`LwFx0(~W!o7%8c_hqnpR&~D`s+tXjQYPR z(c4iEG;Nj;fkA9weC?mG;mCjIT&qy66eWn*KPMkPz7?Wz1^B&CIo>ewU;jL= zQIO=Xf(rnj&EBNMeXrpSf<#;wz5Y@F|0RdsSgd)&+$xf!5Sn+>XQ!;--}&%QQl#DX z-g#c)PX8Y<*)jkw9?3#~?cKFC&TlC_L#22EO8=IT-XkQjRw?Y3z{XcMf}b!akWZ;- zZ|+$c$wj^P>AWp^lMn;J#{4&4%_bU=WtFu@SLkreeZg0`rdjZeR^K)a-)cb%^7BnQ z&s?U?ghceG;BZ#q_Op~zutl>_4U+HvoKN|_tIM_Wo`Zx(ei?Op)U4f@2W87wX8vDA%{}tFMVq>1Q8cfq@Yo-o=c*tPrZ?`#G?()mlU4 zF_kaT-@)K(`Mm_VciW2>7gODfciP%lxE>1-Qu3i7ct80bFqAk$twNT8pNr8WV53{4 zkOCL%fE%yCM3*zDi?tHN7sz%_&2_qwv`PhvTbfrcviu4qxnTPh%MDn%WyBls(tEmv zK2afsQ)Z$Ien574@T(WhE(-Y;K51El7FCx$X9)2pSQYdDwhqa1@BZ-kiapazZfO6r z)cxFF&~UFMcLE`dL9XP9Gzhl9pCy4dEN^8I6GVkw zT#iBJ26BrYEEWhRu~Y59PDg9ARuK_Nt#6v|Pxttwc!F(Bz-tYH-yQf|&_jh4DcZO&)szQv3~J)RK&AeDHBJwox;fQue)l>A2F7b}qR&M#KLX+}gpX z)oo5y!3ST&;abDD^d{^3g}s$Js~@`M%cJeLH~EQE?ThvA%HD)>)|;;>dz7z=()yfD z`|m4VUlqi|`+6gXu6DbL1iXKCs9-=g47}xvVPNa$U(LS?Jlh(fe{m z?RLZjyl#2-UUarnijOVHh;;oGVV+QqbBF71;kTx~=eMle((VKLT_n%V!Y__&V#-@i zP@@$Gqn_`GMWu3ukMiZafOe#JKFC*z$bymjIw|(YFQ-?UUldxnlsr}r>!}!mk)|sS z#;+piGW#CYmS$o198xnMTya6`i8C3)`CCl0!32VkCL!-&xM?*>LaFBNlMHskn32tt z!yV-w1zskl2u8xzsi$oa6rXM1=3>$+0?z3|0CWpU8hS0_g-y>%?X>IeGDy34D0X{* z*A<=5AKIhflH8qyFL*Izo@vjkM1GgppsZ~jH2I313ZH)II4pENa-T|T6=L|F&ma@K zU1!J^aZk+Bgpc6MJq$4B3;m)}3+(N}d?DnC9=3*_^&c%O;zwNJpmmGfC7OxKP z5p#oU<2^oDs%2~!i%`gGQpL%+qR+n3dgm|Dlxknh48i*sqXT#}@XuT=GzTr>De#L&fmF_v*>ePQ$m-hiY zqAyBrZ7{iET>y8sm3^e4ao%8^o?T1)Fl#v7v7G8zGy*F=5 z5R7DMZFjh!2S#DfT`5dIz#BgF!^k=5-Jdil7_xfZ^IkLkbA|j7IL^pDI6}i+y5XQ` z6#=XFYaG+?bJfZK4yv&Uzr z*N1_LC|&9d4TreWd+liHq+(q&M(5ydp}_m#QTQN?e8PtRAm+zUPQ{3{&=NlV#G0d} zc@Gb+Tlq)jPk|NH*ZhgeHhN!Z38Cva#Ij6VwZX-j!KCLK*D@@IJo2O@ z$%uJ499N?FWIYcaVd#5w(1Rdbc)-is5=D~UGi%~_Z=LU1$ZF5|IX0y ztbEXhqJ~I}7_!Ntz$muyx=o#a#S#&S^H?3pkwR;PggLl?f!J~P?^+KV#Ynk005{NlwHikPnO3#&|~8Fk@79jU|*|?pPdTWc8WD2TzV^ z6QPan$gO~WH4>TInYo!X7~wMzbj39dq^}RR_jsSl<8BOKs`b`TmbNji!nF=Xag`^I za(wXI(Lxt}!x9bG15#7v?*xTdsetE2#|BdZ&MENYqR}{8c0n<)`=JD(hmQMI3>}xu zc`oU9{(-U0s3YeB(_BA)|CxH=rDTbCQu>xxad5VjLxgGWE=o;V`iqNXhYVQD`G!T^ zPHLv0TOl}Aj@pGOg|uIbP0KR+#;5VZpPD4Pd;-Pep(ANlJ*l!0O2Np0K*jox`3y`M z6cYuCz261J{Gf}uPTeLBY+4&1Q%cT1tMzxmP&voSSfy3BgLjp&)Ap9-1#ag3e%i(1 zG_DL1e4)f~aK(^P91y#6!``cZaIoxpNJUb=u~lVe0t0x!UHGV^jW2kk%rI}fwe=o! zgN-hsR2E}mG_@iY=p#pm4+(4a1TS@V%t_mxw7PJH;!M?D|mZ2UiW*GO)ufVFt? z@|^^`zE4!=$K*zj1Wd~d3aBPvdLPfNe-+;!lj1-ueOnOdc+}I?@<=EtjIkViH1*r- z+oa~pT%{=gckgo}7IhB@LM{d*uAm1aI6a}JE6|Oe`;?D`7Ln~|k|JNRIpOe~O)wH2 zjiE{_G9q+M?w<0$-DMhU8~0-BS8Xw_3W5G&^q z;Vw_oJlawwaMjLZxOxr@R0oF?CEIxVQS`?RQ1N-yRC=+|Y9GZ#Nd-+%&JjxN= zb#7Z~!RCtYGcxqK+Xr)>l~&O|j0(*&>a0Yy)m`n4ItatzLpQE!zGuGeOqde09fm2- z#ll^)nI%>se0DT^O+@9f;!q_e%W`MeX!D>XPbHO!JSjMI}=X{R^Kcj&j^eJ!5#9BU{H9RA90pRQrVZ(X=H%f zlt$*h?cK4p_swiH5!!od%MeCxE3C|IaxnjOQn63)Tj0H!$euU!4mJCx)$oSJ?@_gg z^RSaRQo!TKX7NVOPQ@S}OB3NW{NNP=h;6KY*HL+P(`j8-L zHjqilJs-JZ9nHYVX)wb3Qzk)9Q?zmPRfCyHlrv9ZV|@T=dH(ZJnC8LaPQQKmRdz6x z1Zuxj{@Ak*z6zB${9?i4lFV_c+f!@w)VW@c^FyZx2V)9DcKo|UaRi*#ECMAalS+a9 zwxyW?S5wPPXCpu2=#Z?ZZ=l`scbIcUzj`C)`8|B#>dr$cg^d;@M$kUXXHRqwm6{97j=+{|t1>=Md&v0`Nr?GLETLjj zm*H7O?t5tPp;7-Lx?&m-CB<;XFYhay z%r;ah3VS5&yl-N3Oyfc9qr!90;8YkCv zA5WtCI?*ih&152(J%iwWUz0PIu>h=>2~G{NqiS&Fa1C!5;N1sYXTIW~{qw4bhk5cU zOJZb0607#dUrgwAz_q9O=^#ih7BT$TR5(h>RX^9c!4LC$KwhpNWv^r})3X{e1bh4I z(8=F*HwArG-y{)L+i*H%00R*Ld*HYkGE0piys+fC`;2cLq82Ixu$=kLw!Sevt?fx4 z74|5D^A{&Eb0#(TN=QdE2A9Y>&j*F8wYwmv33ig=Ud%JNq7z2=Os_O)U?A|=@u}16 zbe*h90&s6nk7VbsGI1VmB0{-v65vLH=&zRAcOPxLpWOa&%ZHN;>H9Row*>`5`A(Or zA$*QC9;C|2!p))Z?gFdtgJM*0wp_8+^jAp?ZV}866n51*SAtf)(Q>?g5{pq}5;K{B zOqb?yx9yug&ed1fK=FLykZ_3CiJsAOzc>4Xq)Ht-J@EekMOHZ zn@oNlGTHbpaw%PC{dsMBV7pRX7IHA1Rq}@9P?{S>^QdA0D|V&QOvje{#^Cqqdc~=_ zm&a7^f*~7Zwll|TvirCY_r>F{OW}6&zC@k0w?JCgUQ|^U%xnd#q#m$9R8lTa z#6~JLhL>+Zewe&>pO@0qYhap8E16 zfgJ@l8k5;GknYmZN-We2hlt)%>jJGJ>O;3hX)QJD@q;Lnunm@9UTmNaTCH*)+B68y zS_9LR(K{&`w1jXqkl-UBYv&$XRvE}f>Zl9JO0-+t*LXcv=IzNYQrcyi`{#x>9~-~H%NOek_E6f2S$CC!MkZTbLcr~pnRiEenTD7fw`}lVo``Ub!jCX%yb5n2JJnd51b7`w+4pr1?a zlVo6rok?0sMNvlCb>yl3+hkM1+ATBP8b;H69?MCS)yAyXxEsDQKh3l5e##F1&8HhH zsq^w?Are&p^xH8nDN_v!B*p3Jdslp9(7UZ4YDS_3&7ncQBGw`khMjCY#~>%_t%#6# zZTO>r>%Kz4g};l)UfZsHhb4^KdI`CNTk@kSGwf-u@ahU<$T7Lb(J{POc)eFj>5ydT zIq{7bcSi$BXgCUwtiXdoxdbj}zG$?1hk@$DupGFaHASh>bUQ3R4^PC?R24z8 ze3QB;(_#s%CdNQPl=BvgzX10CL4*%OFI6QkxTk9(uBm=tn7WEo36msX_zC3p=Rqjj z&2&iEBkZR|PR5>zc*dp#i5vTEFa~klkJ@Y*NedeIPBxnRsy{mfKB`l4)=-(pMb*Tqg{1es605R=OAq`BHO!! z9bT$7uOz{7(sXSw;WHlseNN5R>~McdRou7_>;;X`gzriXK0XFThTXbPAL;pK!riN^Dl{-3?(Y_Dz8=e#`o!;WZ(%$bTmG-v-Xup35ub;q*Wl3e=MsjXy2#} zcAiCSbbmo7JT}ccA1lEYLMi%Ztur6q5Q8$bsV=d^Fqcz>wQM~`EtCCloMuq^Goy*D z{-8+`ZkpXzc{bpPP8oXZa&-vx4qM~qeC}A|vyumamvzW%A1VRCWVYTgN~JdEtsVXW|O zPbsznRz(m$`CL%AFUMUI*0GG8(CBqc`L%Ai$UE$HIh#tGMfT{u47=#nSS8SCs=9IP zGE=^e0fXLi`N|-dr)k01D&ufA=`|Z8Id6{1mtX~Ltn{ZYO5K}@iAw|Wf`gyk#Edj^ zp5Q`(T|VHl04QYO0hMxb^vq?IaMvU^9fNiX_-a}z>ZDEU0YBnB*zE)p) zA8UCoMqlXc%@iJe!8vVUrw9eeV#h_=C6~uRcizmM3na~N-$BTx-70a!J0$H2nu9z8 zt~OXp0!M5W%kn2*Up-C-ks`Rarfj?cc%LEVJ)x~^MRxen5MM6a4HaSk7vNl|8`mR* zGcnR`#z&wpS9oj~R-BZ*Hj#M^oc)EZvSgzbzeEU)+BsklgUW(y-(jccYt!vZX4+s; zvHWt|^B=Gf$yg)|t#<3;bt=*zDPWftS6M2X>U<>CT_mR!78{Oz$|&kQi||uZl8+o5 zoGkb%4ij4pB6H!oZ7ot z?33RM&}VrDU1}98uR03eAc6>xRt>K?+0@9dU8r=3^^!o4_#{MT_)VRD#^&xAi-Ru{ z{FcS*rc+1#qCST1OyR)58H9x0IoVyA>ksA?#gD%Ev z4kqTHp+wl8WbLpAUj#9T-&y!ICunKC1I7}luXqdYE!uV;Qc@TfD_1ji7jVw2?gYTG ziJLQs%$&!KEfLs>s!#myZuzc|ep&hk`!AuC+1bw_xN@Kyb8x!)MRnwJkt}#7Q-<%| zC%OV;GS#1hOISWZH6k?jHIZ93jBh!$%2|t-vqFlSbcbQ1ec^wq8_;yf&OOJP=ZJ+H zFS1@CpF1rJsgP;9_vmRM9QCn8)DTZnWd9`8q0kk6VOfaG(-VRRo<*n3q+F-bTGEeb zEd@-Z7HbZg)sMA5-p!bT?-LFDW%)qw3}P%^at2Xe<&*ka*Aa9#Y<`9P6)btUoyUc# zSc(s1L2G_gLvT(_X);df##7{PCSmw&7#`?ERagK)Rj^+eF+WmV0_+u+LeC7(szX}* z)1yg92@__lQh4GOQf}VCRz$$Boy_Ek`RyB7j(JptBzZ?lV;)AJ(KQVn78d7Wdaq$% z=$T^YrlY`gXb6EDf)$O^7EB2tUq8Pvdv{SAOW*?DlvAGTzH*~C;)%n<9 zh0swv!A0kmfjV47G36oM;BNx_dop|z1PQrpg?4{5NFi)=$oJx4jegz~0z^k@8B z0R)(k8UdqC2qAtR1P$UTN^6BR=n8zuN=qlmCr0)U4xQ!vEmG8_H#(BsTa$%WvJ?9G6v)r|RHa4dT_ussa2v0oMzhOLR}%PZ=MdufJW z{^)!X!b$eaiq?od%FPJM#2Iv$MaDZ$Zh|i>8f#Mw5|X@Tcca1{Bt3V=9w>URU`lCc z2#m>hHYN4(rb7aY$W;2KOwUhJuT0((k+JZg|4-k1wJy|ab5c3=guhxH_o&xFHwS88 zqF#P>(>3{hHch9`t{sP$4Er^=dJk>kMiD==IGKiidt^G?+fNJZ{*qOdpI51j0knSt zOvI-6VOgZ#O1`P5qm1wfR@`(9=FLqd-|A<3UTxoF`ADDk@Mj(KQ$C4{L{O3s^DS0lM8yP4#g=vb;to`LY1xg z*1v{mS@-9Gna=8X&&{&dQOYALh{v!*Gs=?dc*)RAY)RDzg;7alk6ApXzo&<%mk7G? zrSImCZ1Y>+x%KVSf{n-SO-PL)g6*cgxbm^@9lPE=p&|OQ@obte?8$q2>&MH)4Px?s ztdo*nSPH0;+Y|lT+z-{xHl*y}(OwM$y=hw=B=tm*&3d|lILIcOg2FZVei5!LT8WQC zq0mOxDI3b;6m^_!=Q~QlY`P2?wX1W{FJga9wsin3abIsRM)6SF4 zM7kvNuakJkXqKQGeGHr;U3OQehAStg*>yD3BYDq0-NBhprPgF!^=-2Cka9tPp60)p zO#?wlRU$Pk+B*u&UC=2jR)$$_$+r;=ll!Mr=-cSuQg`DV}eU_{-lw^K52-{L7_+K znQrlcc_a7q1~TAx)9DBIjFgulI%k%U#IDt)VD&o*4L|&LOV#OEaS-LDi0YyV80t}n zwGlg0wGIeqGPLdlwcUo5$`!ux5>3xW#Bbtm&B$uZi*-vd6y>TH3%^ShKCx~s;7ScF z^CW%i*VYgcu;Rbj;JNuZjN%D<>es**l?~DG!YI8{?qLgxs6CU;tv{I@s|0Puehi~m zO~Y0iV&gGYdDzt-=Ih)lHVF@65HDuJ8Yf?xAJ=E|4x>0~ikoe+3bpoaIn|W4Bs_GH z3z8IV)AS@7hxHQysV{iwu>I-D@zG~$lE48PhrXGB)1(jP0OuW^e$6>o;3MsV?q5Km za_1Rskn6H5E}}8pEM>ee-AmrkuUErafT%^te0+~{h^zitM+Al0wo`VtPI#V^OEUZ5 z-tNf>Y)6xXu&G@=b|6qWq91lP)#is>3*5Yan($z_%3}s?AgBcSIsRkaM}sZoMe2-7 z&k98p(3z_HULBV(^uAtQT`p?jtsquo;xK1DtAocd{)~ZH+kX8OGpeRjVEGYgFn`Y_ z*_sOCVWK>)TwE!U9WkPqyC9>fC^?(C5`gJy6_6m8z2hDtJ5|^UbRowxf)B;ow8*Nw z%(=|4!i{0$6}UlX0erH;CAnaJsxVe9?h1Inex-BT>va{ZEEN>J-E_|w_G1J_Slr{H zU+y2_vE^`T>3tYj+&}ArVl=lddgNviI>g&CM1`^?BUM;B2Q(f_V-F*bI}gQZ4=V7&F4c;V&{0$laTiq!(*_%ZOSD`s(idh1{Dd8mBRVzB}Un z`hrSstjx>|is`l1vHAt{9kGvDrIDQ<>&)I`CYB+YTm=S#DA6IO= zw(Celq|Ht%loUto{W`ZN=LSE2zTTJAZEf+)YYl2h0sHO&SdadlSk+6Bs`R&t z@98@IoZB9$X21P9rSR)U;vBwmA zN{sp8G92V(?&%8sqYZ$8KXa#6-j{Ge&!uK5H6%|!QKBgeRK7panVFT=_FW|<{%S~# zC+0rrre$V5mSsd&*$kl>{U+c>s_QgrKAAa2X_9!?9{Fh5gLCCp*BR>CuDYOc-TiWf zHm>^7RDH1F;C?y!jkpf8=TG{6&@h^TsTKtncXxm4IZeifubZXgC(dG3)jm)JFRqA1 z$?cAIi>rg>sr0^=PsP&)x`Ib`XWZ<-ONo>TInRGNeB0QYAucW*$i{+d%~l}bw*y?c zoL8Y6u9+EuraK|)3G%ZKbx%8&a1f6E;Hd%%WxgRDp${R4hkrszM%j4+LhFW=t9JWB z!X`V4ji9u_MiG-iyinR~L!*w0RzLd2smc*}_-e9RGD{8vi~k47ILOL@l1A5(S?@GkY76Jp z`3EieH?4AY;0q^5%SqvIUX<4fcbshOk>uz%pBAT+^`qmZ$ssNrcli2|6Hd75*$ZhcT zW*Ao&VOREw>DeD8GFpL{-Xz#ksQ!||dG=foyY&LuM5)gGQ)aZ&FBWbiFKap^s9ext zQ{R$Ger)y!y@Ow8MjJPzRLNAMC96fW;3~oLwM@4UrYaItKH*s)pCH|1|1M>gVI#89 zS_i3-^mLXjWuyRbeN~T87|4(wo9%1Rm<-c~(PJ?MvyyJs(2{>xg~F{876pfc zReYMst_rXyRC>MyKh|z8R&{O@H%RVMG9UzAH^3&SK%(}V%%1dnqS$YR_Bq&adF6~9 zF(v}AmR(r(oMTV;62W*oR%)=%v@kB-syYu_5Hg1?9uRLSydy~(9#DmgL!B{yxsey( zE43t}Rk9In`K_G<)4v zwNRR-^y!VqNgF1)BWytZOVf19R!nE9%jd~&;n~<&H*Oj1>*rddqg7GY;jlJ(MOjAKytj*mdH5QgQwaNZCl7h+QgL=^hT+);O z15Izey};5CjL5LETJP-WyJjFA&*k8Sh^rgAq9vkvSQ&8&X=$uKk3Qv-}etqQ4K} z6jmvJ4UEz6eL!bXJ3V(=OmiPf0w($`lwq7q($VyAm6z(Gdgh6lR{YCD@z?(;MD3?; zn#Z;}=Y0pjLAJ)fYA?X_e=YMR#OgeV;Sbxbc%r}5|A3nQLjk_1@&E1F1^($jq?d2X zzX++n<-NpP{deMJ2*Bz8`V2r!mjd=}iWz`e{Z|1mKwB3~PSTo=J*_}?c#yO2zopi* z4dT0x&jAQK)N2%Bdfvn}R}&kd@HELjDy2l5e6=WRJoJe7tGdR?su?%MgVZ zP*(t=H^ay-T?9l9e+YoXE~5fo1{nPN>?05+?gF6u0+7bvI{UIf#+NdM0r zAo>4!=O2cbvF0w5{I4u7dH(M#{y#DW=>JDC{wecivHw-7|H|V3DE5ET|G!o0{}2EF zS*f>=b*A=Ok~eH&!hhv;nK!!98GQmPoos68Ra}f)e?DmlZju~VYV44ERc1ijd*k`u z#(Na~dWz&1+not(ec8XV#NRnrw$)!8mGTyC2*oPc&2;EAte+JQm%8vi2xcJWH-27MKgqxzDTr@n8@G>nT!QF-t!=nUms4Z&n6gXXCbVer_kCh4`tt6#==LAZ0 zOZkz9GFgy_J)55}!KSIr$NcfQU6biEy9xVeB}OL?15No|PnoMA21C1pqlwrlpb*WS zy9|G|5vaD`7-+vFzoDZO<{n%9w9}|2(;4k59Ix<4*EzWgvIQ*HNSUHf?V5r??hZPc z=gBk0W*FaNcjokh6e`i5Gh>SJgv+;|)d|=;u6Y`?_#k?aDudWFsmhDK@Q+6M7{F~lpYsoTc)|73 zQhZHyFgnI48}`bK$3;uJb)No({Kd)BlsV=W{;A#7$?d(xX!J73!aC8X5gWXyOT2`b zciMrT{6^ZATTz`HI_oIPvv!$Rf)k@Y7gZ&NMW=9S)cGMKJQL!;!yu;GizL_QkW@y4p zp+xRmn{Xf~tp@){StZg=-CQcLT3?NI7X|{eYE-|u`9oA+IL*c^=R4a=_p)sk$h51w z<<4B%kRq;oJ+z$Pwdr7)8P%)f_6F|k7djGXx>q^}1kW~3ukR~i_)T zU)j^jf-kr?a2!%qx+M>rln>uMZ=wEzwf(_8Pp9a85_&BfI13AV^JL>IM|~2g&Np** zErXhhZPm}ji7Im9x2))10(y>>yiR$Efo7YbO;d{=rcb?9fL`%5wuBF^I#Gp)S4Px4 zY^LKP64;pa)QlvnefcH|oh`ZEDPZr}Djf0fmwtC3JH&fB;sGFE{hX!dUcrhk{r8)< z-LFRHy~oy`Wp%yXC;PY?@6L4UJtoG=RM7W(dVk1Dk$n`ilWJd3aJ)94F)Ta|FGyUk zAA6(R{6>~|JW8a)r4X0eu6O=$R#2OyM|heAR@m(_qS*eDE9`#5)Af^A!d_0|1^KvP za)Ax0R4J{q4^_#fetXTsw0pO)f1*LL>nB)@gW3M-wf&Q`4DUm}V6a;~ixEuyrW1NE zU0X$PS5L2b-mp<=FMl-VuQ9(g-KW*1J+SkzAo}i*)bmsCE!tD11B!k+jXzGwd9V%S zF}+hVSM!Qy;%iCal?8;jLwlW|fi>5diFQ=O?V7U8J$Upa5qR*$3fsAf)1L!`Yr*==x?Qxxk*qJR)gEvB^I zXzyrrJK^Cd$v~91F#q1k!Y8zaI^4!XZ%FI$jtb+OALq&W?o%6UJ<{%u>hMahOk@dj z%d(f%4E6QLBE?>#(?JJ)HUo9fiqCq{4$*WTA}gedH5D5E%LVT7HvVq&>|*As zDAyMD-i=ZaAw~S)NgKMFT)ZuJc8>aqmV%eV+^4q2NfnxY4IKp;O^eWhe6}1?1kSgJ z-0LR!1xLzOj1uD!8a-5$8oRF)o_iaq4(sYnu0e2b%WzfEKfQpdN6lO6-f%ZZZ$IGf=UkA zl=f@8rWRtFHnQrCCs5(tdH=&S7<#xRCj+sH+q{=r{NN3*R1N>=ZY^#rM09O&2?&;C zGxHptdv|x;?uKP_fQb*2YzzHd**w%bYEJrw{?L5+2_tZLppEgaw&hrHKIculTHYzI z)|n_Mxwa*u{Dwh@_d{bw8}W}GSj1EF_9oI{l6gS!_jE=Ctmlz;CWFaKJxc3o+)_#D z7G`|Jn@t8iR|cJuohc*cFh4mx28mM&)$TrLGuY`k@mTBq2_uSiWt!eLZ814irrOO=4)q==?vezEuogcqJ%jU-)$LA*(YaWjaWLe_LPj} zx%#e`pN0+I7=Ih~dHdFTDF$8ORaj6sX+79Ej~Z_zy&5*5simPsxr6nb4jEGHzp4k> zNcofAf5V;hHq%%rcEq3RmSOw|>Olt1p2-JMk_7L7{gPNdsR(WW{~WNlpdkOKl6A{c z=6x(xgL83dioH=9-L-n(MWoOjJvEzF!n7KK*upU4nq?xixQEz~)i-9Mi|}}t0j@5? z1Fkl}(5*I(`VTENoHrTjF;~WNM{YZhy~R>uHiVh@qsSp8OF>wPK#0=EJScaAPxVc+ zc+cJjif=boca+*`sfG(yS^1xxQMJ%J#N%ALf_bFTkdeJc_OwSc5Tz#r6qvl6o=S&_+Q~LJ)KFs7=9=%wfU&#*wQHhTvv+MfVCZWWRQJMf7p3eYoG}p`(vMEX*`%-t;WJ4dIzCzvKIeNh zrztlf8&P;j4F(r^{u`b6rGYK`%DY{vd$t;5gWleNBK8ARGYigW$9d{RlF6lHMI|vo{OVW~R`To3BPyIJvkh z!X$nUxj@6e!+u$f3J|6mQ+GU@Lo^o2rX(#UY&WWe;UF0mf5hmYbLhC*q&5{dF&nVw z7U9=W5+N5(gzI-3)#y~5oDGGo*SXqYB$;K?h|!3%I5GFoe6~Ck-L0UP4Dd_~GvR=G zjY*fN-uKsk%v*6H`*c!1$`4c6QO?5eDrZW{u=`Z~4rIJ3L<{kG7YW(mw<7ncP_U^j z3dh;kYGyh-SeMfr22LIJGBSqplShTHe?dlqf8Bm`>apQ7Y_z%s%6sqdOeV>eJI2 zFML0P2{;F}AmJuq%)`r2S%2dcUCPPNaudP}zg2VZDp!R}bnj58?AbVoty{sJh5DlNe6Bu*Po8r{Icbw_^k7c+a#>?u zl!TDMR+#Lu749<#HzClH?YFzg#m%vtyNy?o>ntED!v>5yrg)y%VzHj7cNXI5&sTos zn!pLUMkjC#6pW*Zgde%?{O>oDf9bMH#ELb_+DxA2Jh!8Wrj?e%9dlU+VC;XE}sm z{k+6M7Ke1H&U<(0kUcxSSVZFi2hmpcj^{nN{La_md7sn|PDq`RKVn%qvFtzM1sy@o zDQ3hwMZig%BaX0x$3LsqO>h^aj*(>E%ETBb(sTM9NAF2u_nk)xm<_~rP}~EXquU#mQL)w7Ysl}g z^y=jNB&4OoSp+j9`FO-%t}&01}U{e3s& za1911WD6lur)GEZ&5u(%BL#va_K4Rz?G<1)8bE3d$Je^=1aSv(7}6|?JaO0GG=tc) zb+x)9B@YC#vxqW5l*ClL*+v=+1B=~hs|jj`@=qQeJ#yDi5c~1Jn)0G&=WHODBrOaF1WSG#m4tl`G=SLO^zF|n5Z1j1_x`vB z0K`lmX2f0N*YN-pcSDs+a(Gc^*fLHhM5sjL2Q0^v5RfKebA@c%cNj69?YoFx8@(+gmXjo)fvXACxo+68o;1kM1`nbUl4Oi>OL% zx9))L%nPx37n|KSm0~KakdN#vc&;3jW?tEmWS-@`PUDyiOBK2Q{`XB-DME!r@_EE( z=7gp%YHK%uPIb)Yh&Hc=#!#fpLCUyaEjU#Y-ElshON-k->MwWDETml?r!>A|x)3Kx zO$@zi>B7W!=a;V5(})=-BDl>#G$Fn5OSwPa?uI&k{iLyb_gAGN|EFfjJ-GZeu%FVf z>v?rMr@?4-1`PD#8}0KP@#)NS6n%3!Lz{*ev1gu4Q%oNZ!dI*9gt^qrWxZKOGv&@x zr>aLq)(yn|+9a4>n?XOoPYqb{|5&R>@Z&-Z%-f(9ZNF^R(&35(U$GwaR3k$M7}?7C z8=qE~XPi`wg*zep>4>jT6bLy!3{xcvnGhNuwzKz#CW_vF{H%1@ zMf*p^9~lIo-$ng5lDiyyGPv%m$&O<8;HGa%J1zCBI6Jb~-ZZnENnxt?v}Pbj?EG*` zawf2Yi0pvji8v07l;b*G4)H!}4JfklwNRLRn3c8|5i(^FCvneG^M;iLfwGCHa+07U zIvW9@?>1&c%nFbkZ!JDloEf`yt{T{(Ng#2<+TJhtnub zqj<>0wHX^(nf71Z|1v-*fXQ&&gxKF*C26MM>my@t7DRPTcR@l7Tc%ffg&o@bURGx> zReK9dWkJXUjY~tsLqX5yART*0O|T?`*Afqp#Yfmme1zV>3W$FI@{}%>;i07)LIp2% zzB6i?FVZ&)jBmY_^vYtwbbb3l#$rOww7rIN6H2uak+RDwaW-Uzzw{(60GW0UFsVeKu$qH5QG zQ5zKj>6!rrC8cW^N{~+J2I-C=1q7sf=nm=b99lpaO1c?x=uVM7gRk#C`#azMd9L+m zu4~qM;?C!}Gsym8+1aVh@PQu2k!JBb$0Id0=9|?f%?efWJ+$qYy$W>LLR+KAvA_s< zl`*BLLy;^BoN~ryQ6gGAM z^U6~9>$jcS>&#)+HfX2}A)Dt9YpL76tzD5!E6Y)7M|jXpQa^yRT!~(+hLFw0s6_Iw z;b{Io%I;Om$r^{@DC6G*S=rXGSW85yuJPQs^gd~hO0m~yBpLm7s&*Ole{;21BeJ;F zszC^Si6l4(33`c?Hp-@siF*Wn$oC${RID-GxE(SnaqBHF%$n1XZbLE}ihM7zkwKo8 zXCyOjC1!?{317QWpjhX|v$4IY7~9i3IUhe!KPZb?O}E#}lk#Jn(zxuKgZvWaU)zh; zDr6wP7XG~+V>s18cu0ad^lj@nmb>(OgLx36jTN(l(WUDwmy_`isXF{Hq}nqo)lSQB zOO+JR?fn1XUpJNg)Xpx}e9Mx0;z?{j08lSYLt zuFk*01xg`-_uIA;pal3$?5~_cMU4Jv;waWH5g$GgQ(tK7g^3ItV9G_!XPBkMS#GWs zn1&oZyzQ!dF!8;FCA`))#c|rO3RY4SHHpi=Km5^8*mvS4mGJ$I#-oc>3ajMc%iZ+GKdWHGJ9&IdJaJ zzpL)rwyzJTv^BQ!@3C`0Pk)H;NEA!2rSnd?4sSl5wj!-Zg1j;>d;ltsT}N;O-zP|6 z(|`T0{pqcEX1}5=!5m)wW6bxj7KPa3XTL`{HG26x;PXY~ z79nm=?vB@Qhn*&)j;{fhkrXCtTx|TmeHQww(}wph4|$BN%-;MYO@3N^>v2P`i6IR> z33Zx4hcNEw&Q}e%d5%og3jC>ha_5@)$Er{2jv&98D$PJv-X5_Xg?QPuaR^@iJ{0ts zGrGx$70_N^u-&zVXMN6X`O*+7H_>ur3wyEJ$up`RDc1hUsk&YolTZDWhJ;^hcEByK zPkaTt;F+`B>YjGThPbf_~2talKto#@XBu#S2+p=|&8Du*Nx>|^%E6MSRu)D!OcQA)*I(O@vith;X2uyVk| z_&$Jl!2G8!c(HN1WXa+42oa+BlFMlA1tFSw#>zAI$F|vnq0vIOoKHdw9kb644yMy} zJpUACyK|+y|C3){8d!j2r&rV`&GoRAH3&w(q~I{ z(Ar!i6!k#z676(J)0!_YznGV#-1a0Wqrxqz+HXyehH~Pk$1(p_Njuc&ZA*R#8QD}v zs@#>+`HHd*{_&om(s4gv%HnxklsF*d%uCQFaeLnO0xI#Fv2=OeFGRwg)(%6`qb`}K zObR{RxDp@LJO_E4AFb|Be7U_~<2Ye-LN5=-#LbYQ#Y`YC-(=&AXBU8?IJM0Wcy!M;n6d73 zWwr12OC#;(?)jjJ&EQQ%)9Lk76eynBf(<`Kj@`&z4L)fC(ri?-AEC}_gP8J)8-r+M3g8`*!Plj2qaB@5-x}$BB#U- zYGOxsfCBa>?1y@%%}u zx?|V$Cxq+kgoHJy?*aEd)mb5y^sLD5(vF?0G=e>_d7Q|>dq?2XO<%TK(d9d@;U8L> zO4AJrvKagIr*za@Eo7P60X6@;DXnf2`v$CU8%Fx@UwM$OVhvEQaP>e*57Z2c1k*6% zsy)|n?IFkGg7D{HDXtCgdi(@?BUDILi>t9nFQqyC;(j=u zoWRc>>aE-2!*{{a5f(UHjk`T2gs#`}D`85&Nyna|qO=Povqu_0YoZ8>_96VXXw`0K zz9TPysh(fv(H@-}n?veRWmx7FGZi2Aiu_guMEtdZI>L0eC5z$If7&2Krvhd+dX`C} zq_J5}M!CyD_erCd$WS13qYI*Eik_$9+2pF%j=qVnMMV46C@d`YNtB9ANw1R)$C;Lf zy(dekaY%cqdv(Q9yR}N!&vy9>FX_VW z5?7IJ36jAlX|;SQAvec`-c@rn>L*o&smc>Do%8RgFqy#T|AO#)cUa%=&o>o19)FND zX@y9ocHTONp=$TlZituY-6Uqp0+; zM-7gzd%?q6a$=H34{&f_d}t|CFGU(+=&(F4eCeeVU<#8quM{D!{w|DHiR16X>8PVp zD<4B`?a=Q!-e34}qH(HrKk27SyR}C&N{4jszm)#b<0QMWMIb>m)5h(NvDYqw}p++v>HmjJ!1`KNR}MLK01oEqp(PYMu$oI zK^4u_@Euaf1T!!@GB_T3uxuYxYL{l%HBP7xNcHNJA%iQFH(|RMvOsSeV^>If?Jy== zjY`G?z89Wh&>{hySa7MtOhS}uLsQ2X?YL$hlJh5@`HvsX+5KHc3w2URPJi)DSBl}! zpQUYNlJUWen7(?7?WSmw@;O-vzv`2vXJtZofoiL5omV8c?K3)w+&)E{nHyZ&%wzwe+0KTwvTkD?2eK#MEtdLs@tnMlWdqlEQ{BDt_C)Dih1 zd@s~Dr6+Bh#iY%HN~H#xY>pvigkh%9O~FP4rK2MFb6oe<^LjE|9BzLcz(^CBjwkcb5D) zYVv*7HPBh>J;xW#G$i!Rxx`#<6rUO_-Zt_x1^G>4RdaL7i9}de9GQ_l3FDH+pt~b^h;_D`LUYZ`-2d+<+MZW4bj4g(>1GjEF6sRx7B{;%op;QE~}D6`WaSL>ubU>isaAY{1FqyPwGeSGQR$DH42ZP9jdm&J; ziK#ic1T$_4*K)3$uica1J3-oJ!2^Uov3L%E&Hl*!DJzbIDIBW<-(2a= z_c3Vk*VZABS`oai@Ag0w;m7~-z{gZlF(y<>^}Vly6J5JdXx43SKvIFkYGK!=e#NKl zm+J$cIq;IrD}1x2NZCS`E8W-FPV9W?0@Ylc(wy*UZaT&wPJ06SxyY3*{xvq^B&Z@K z^ENY(gx0=W=apZ$k-w%&!@es-Y#8FYue1$|`b!B7gK3o=sAB6SU)s#t-^CTwJjd_$ zp;I#uLq)csHm?A$?nxDi- zi0D)tnUABMPuHCp!d}C5r8dh#zc9-{##O`i^5jKogyiE8)%A7wH@gz~45a8e zt8hzMa(tcK?Ak!!_u>u*Q?lkrkr*5f!+=a|dnV;G68g(wnesfrun@VEh@e<#;l9V6Vf;)av*rpou*QqUi`_?w5A7i-wYJ zIt#&nrZh(1Y$iaXxpgTu`gT60=gjv)-Qcb=Td-f#uo{U9go4XA&Un<2+iqp#J{d^N z4lgxG@~I$W)-dPzd$`LIDY%qu6jHk2R)f^Q5~ZIka#YZIwub?vCe+yi(bN6Ae!>4* z|A6#+MgA=AAm^f-D*KLf5ikCN%k7YXrLFOVWiCTt3K zSHq;|fs^<$&GPUXNk-bRajuZnhPlcDqC6kcaY$FY6wpM(4<&%_u4cS6T&S?Rd*24T z7&PD_lJ|S;Avu!4!G0X#!3~A7&9R$I;{wX+kQYz*3L4M+f+S-6L4BU_Esga3Y{6mM zzb%Tu#o1VeUnXVHJ7}k|)!d)<=p%l%?qXu~CeK3c@;y@#EeWf>P_`tn^JK;Jb%VA} zB4J62`&$P@fBkGB<5?|qJ3jX#2MB9m>z#!SCJ#&kKG&qPbmC`}v?5yTKH&jPtnY*rINX7gLwvvRGgn)~5lx9AeSRR+A zS;~)#WM_hldJ-_LmEgqaOpYn|vB}mU-D3aX^(z9_Xpclm--B~YM5bd(1S>orpEQ;d zug7Uu>?pX1)2(F2KOoC8pMwd0o#Fm!6zgKVd0*iyV|7-chhwwTuwU2G=AClJh5?Nj%Oa zLcu=c1th}|o!4=>K_Ks3@5rZ(si9)b21h8*5a^<~{yzVVc!Yw!MIG*NTxjP#ONU zrQF@P2!c?EHwJ&-PY{_BRVc{WLI7=3f0P!V$EMu&-MwkZQy%pdb%gsFaTtPW}% zYQAqyi&j*S-kL2yQW8#QUlP*+{+Y_Nkj%I`BquyGSibYB91N4W!?SX{j5A3}l60qP zVsp;G-W1GaubCFe1tg6Iofk2XMe7YP(GuXLd-HH(9_5LE5#Bx=*KpsZ>?uwwkL=jql9Gs+D@ zkP>0`SdLgM$-qJnSwGtMN^a`K(Bo5W;~9yjil_eWPaE~$yy%=uhw7+)el4$`n}Sla zikWY1I7aqgt$f_7O|;LmRF$pcamt*|h(&gUvG4s(>pqW762+3K0 zGgkrfqD>`;hvZDO$YVwnw#A?CUS|Ua6zhL1fXFSNQmmA6WV~_RE^1{$aq}*@yh)i> z)BnK{#90Pa7Ua*CJQ)SZBK}Ark;7GNPHR+}#SraFzARCIV=+`{r1-~qGmSD6i28Nz zmUvnzA`sV8r=IjgnJDiJQSx~|A181|v%9c_X9!|Fw1yqK-Be{%B!2R8y8{sRX)1u+ zO|)Y4<^fyc_zA_e63>JIkr~)}sCHb5P81({O3%%KlOqmzYi&F*SIc1jv9^nb)j_Mp zj4&?-H?p=YUNEydZd#DMtF8DAcnA{UTsp}gEyia*T3Ena_Z^|2lfing1Tr}5mYR=B zYoUCS9Gk&|U1uN1@5q$r!4Ovlo%DYg!mI2pWX;Aw@4oJri=5HH!PfbuKR-*ARf=lX zrZDa>K4H*3|FrZnJS!I&>L=iQMueI9+@cK3w>ycA!Z%7yelLXZ-PuKL>gCMVkP~y^PcOv^1y%NbUir_a1gwllfm47QC3)PvC(sOp9R}xyIs>T>tKf4*>SB z1Gj51ePWr#W3AlL?WO#>7>}sqj%ViG43?r#$4jsiG%2TlPAQtbv@R8h-ciYFYdYLR zEOrrk@D{#upC5dJ!tR}IM`{=n=5={l`p?>fZkuYK>}|VqTAzdWUYmV3W9?@1z9gFW zu1i1d4b`fNZKZ2&v$886^ZP5v7IC*=`vM}Oh=0UcIgO4k589ar>6zFDEY<|?$yYzk z#Ks8=s}`CNBD@5(yYTEk(+&e zn6k0AMv*$I@;VBxciJ#59hr2A-0KeefQpvP{Oo=m&s*mD&v!KR>Sfbx5>pnzUgkh*)J8)Jl8{M=Er|`)VD~!iS)R# zm!n6`srK^rhGGQSa&^}7=QUJZ^}q1GJAwD19Ij`{$@AwX^a7Ts>ltc0cjvA<0dg>V zW4RiDfdbOsrQhxQUnATfFx;Kl|7y_x-~PLs;{TrS{au*+-J-riN4fEtUMpg#K0R7a z8E|2y4Znmt)K9NLs&T*$BNLnlKQ^| zJ9Cj=O_=pE@uivYlX7+(V@$iAzaon+pIHAn(4Cje$arbUWAJpl&t8Yw`%ng}~v zyXxEqi+au_$hCUbR!W7hGIX$MNg$>sf*1@u=66C}D_6s~5Fp&0WVAthf7_oEt`Fc= zH;Ju^-<(KqCuOf59wxJFdwd!HQtq-hu!V;ITqO9v;0|=|6y#WdBf-|r=dau(odBrf zU7N69+uXF~W*p8>RYA{5ogMavA=h2E%;3_wwgz{L$5S`;JVoSqe^LEs7l=9V0AJHe zn_}h%xceJmT~P1!I}6e^$TI(XIEO|V_|bh-?!kZM1}sKz!t%VJmjbAp0eu0ck6y#D zgW~a{k00ek9t$xqKVAfmlv4<8F7_}<>_jXw2Q-g2gKt9S*xuvta6bN)vU2N-ylK7x zLZzT7MgTYn3IT+4>I2~V6>6bKwRZ&Dt-;72r5BO$eQ%l`Ti5D%DS(+FHwQ2<2XPd z?$~!V{PY>&7eKsqY>e{G%b!|Yqq?_=H(51%8?R4vf11pQ4bVbKHD1RvVDOd`a5iv+ zmfcDZkhvaD1WKrAUOt4PmjwEyZ_shO*Y50S)XAOY)x0&SNgSvy$dx%W1n2XaDmaX; zD5pNQI^A)I#tREanpX^d*{v#nB})J|nx&wpaXq$0)H^#A3-X+urxs#_FA?>+XAx?hpMJa7Ax=j^3m zSihG1X70i9QO>R}G!tb9F-g}g-;P%K_>iL4*6T{>1LGqB@^0vYx0?tSD z9{^lgUJmw^TDp4&iH~_kC<&iy1TFa@)3Sh*3JKraM=*}R-1mIW=U^@d<272aMf5x; z@wOD&7w)bbDkR$_W1CeqD5>_)G<`rA_j=-&*WfIi9Z!NT5N4p42O6#d!lNdBg zISFx1Tg;d}zG`MiYTsIBN)xPSPh1L?N#Lm^uU>zKGLbW2lhhTVHR7vfk~EFBKZ5bc zscB|I+@yX$LOezIOjGF2V0$;4NSOWpBRDPG_lf7hwdmdwNWWd=N7MQ3@wqorVcqkM zoq-cBszbSl{LtO<{$^QrvSCmFlf)cf%4 zRR=Ry*W=bL!Jv9nTKp(pQSHL{+ja`g2OP8jmYs!%4@FG1Ttg9>Ad10z8}~>XnoNDY zc@U@X*a$@}rbR=(0dB$SrY`^y35H`I5~>d!zvivtz_IDYpN0yWC+aNKT2IKF(&a{ClIR=GgrK(iu%@W*&c_C-_(OBL7_z_CQ3Uz>#flEr(l zf7No`Kh4{YJrt1M%MrE+5;$zum+G(CO^Hz-U59skNk{=>376vUl3 z&aDe(CtheHW6Jk--B|*;1vE)J1DXazexO`6dI2aW${%__g8l&H4|82p0H`m8nq)6a z0>rqRl%j1Y7x4^PN(k{P@WHN0QL>WauoN|?y=k0pUQhs>(+TsWp})9u89nU!Y+0a&dMwhO#{ zo(_PZYJx)L_g>R`2a9}gULoyj>-nguhaTBA;*|apUcg^bB$L-y>mJ3uX7VJ~MIn3$ zJt(>pavY)Y0WAP2zRv=vTV>NwyyssP!i5D8lZFK+?3sS~FbMzLBmeH%hrvJ#G17Ws zf*H(F+E{Ej--bNqgNuBh;^HGGujR5IhU?V8HQYe$T_!IF?B6q;4$VuG!OdTqW;g^& zHs~)`Y0#D-Uy=M)3lZ^~{yv9aTxDeDUbI=9@^2BuXO=NT7?*qhN~3?c3`JcNOzn_* zF@8o{t?(u@?j_J%?QY1sLxB?`@3HI;5i0~DRO-WANnbzJBOcuf495Y=6V5})aRDxN zl!V>zov`(ux-nMoCm}BL6C5A#ecjTrV1fbh_%#R5Y|##hPKQ)biTD-+Ahq%&Mt@{J z{+mbW4XS4%H`$**Ol?k=i_1_<5bG^sU$Z?m`9?mXvi$PlkIvE&Y3wv%6yfDJ92f=WwxC-qF`=D_J$Q#(Ws7UdSnc5nL`&G{3k+nS?= zsEUpXT^+TSaZz73`Y_H{UcWC^-wYNlR7Z_AwYSV4-lvGJ&Mey@1c>qef*{t?PIYrh zF}v(pcs^+PEnu=>j#AvQiW&8v~>n z7$Q~5y*}Wz?FB0lD!zkZZhwx3NQ_sk9|CRp@>KbhmvDHD>JhW7i9PI!C~IR8BpHeU zdw?GQ=_DZl`e?%51U)>B5Cqi_6#5hrp~8X&Wf(A{p_}zy&c{QqzXx{_dxuwDVz(W_ z!{c*~ZR3J>_PFXJx5M~n2a7N@lza@EWV0Nqb=VyZ5F7I?3fv6so>d54+H=K&6OS4a zal4Gs7(3gh6iDy%$zDXL!FqmL!CrKG_=5(1u*uCa+7wxR=Fm<(_oH{RYNU!%If=dY zMh3$9p=`F$CTT7}=(_$bszTGA#x=wLfDI17WbwlGlJrQzwsh_73P^qcfm?XsxnM@qny1V#s$!g@zCv z_2IU=)osu!PC+zdmv&wqnfOCa+=I{4WO+{m%tUmjEdXMCzibf~2kP~1iPj*Z!Ok-- zz$EDFlrH>#=yxCFk3o=i*b+?4)AoUv(rXM9abyvowZ(!`UqA@q&4})$i6f_+RHozl zvPAiuZJ4B*0!bR4?WdH7J+GiVnx?_WwRl`j!7lky0T09>ekhJ%e>6Qjy5h8;+u^^- z06?3aPo1R_BUUwtl=Ae|eQ8S2327IB-eJEW92vz3GJUWtEdvXl0yL9!K#Upocz;LY z^5->qA%j^A%Y0QF#r)PtRHU}f&rNlYuKnBn#!);`JVr_cwNd1GYV%NnK8a}()dX7F z7T|)~?&s7HE?X^kV%5JQ7YQN=>AaI5C=Gobh$I_y5mb}E#K^= z$@`~O=l6_wQ^-8NLq_!!WoF4Nh`4P0^w(7>qSW)X7*w(R1y{uP1(slQ<8}(A)z57) z?(|Io-_EJxgupV0ZDr(1Bo7sp*#0%i5F6BoQl?HtXAu-`?-!yhvw!hpWY~}(_iWrD zku;Xr-7ib2QBC6-1DZvK3lP&malg*`G6TT*l&P+_}#w<{awgYa|i( zynJ(wQ|x#BNb~U0Neq&5D()Ka^bNJZmua}mE59qLzx-*D6Yy1HswTlN26ut%1d3_dK z4rBWI+Zt{^d%R#@Art$YT0I0!|Cg4>B`dbhOqKI1&IY}!TKYGZd3=F!jZzyhVWC?q zoJWFaiTN$GKjx*WwHBf;N`cnSo#?tZ?{B{>ZqxQyFV z+R;#TD;T*v+I^8cA7!-%D2%!VwqT3n$-Ptx&be@~fQQNM{+3dn9@D#Nu5`c&vl;S+Co2QaP?D`yf} z!6qke@%oEL!1ct8Hm_Y9`A_uP(SZ@e25Dnv3Fi+@Dxr#eCc?-}-A!M|=T9V=-K$El zu1uY@2CX^J)WM7iUegC$uH$Pmzs9|7=4eDz?9bPJHi}7!uly*N*$cGH&b(S-zUNqOYd0OwBqk8$`mEUrnJYlI`{ zDKVc4opf{Thw_`0E$&2zgy`KNOh+xKxVB&6(^b$&o_&0S(gDLsL%)LytQ}%Ri~B z@2Ji6PM}C&WItz&IejWF&u9xK9BfD^{G=b&=lwl1~;O7X~R>*Cz`%6LQ16zh>ZzBjoeSZEZ2)e0&i zvfo+!Jr?I{p8~Ym@3ikf{NCKJ2QVN z$Cap^af$5$^9urMs!=o&SM-?&@8p~AVv&%% zO1oF4qmPho^wZ-^HkOhGROJ;a^^_)_2Z_nZCTMgtH75$B;W1PtIu#5Ha7lH=T$@Ze zdGy!&o2?@ctqknwv%`bsB-iL(H73>?tMLknY7*zj*!PkG@$}iKk$ffzhfDb6zgJ~u z6V!mmxZg_TOiO9~W92IiYG`H($GZf=f&$EXpUajCv5w^l{Gaq*>wsAAnwU5sk@_I} z^}*9vxr#AH=@N52f6uc2*eLJ3ia+C^r1_l}_bFTtcggPkx8dv_(D?&lB(YrJ|0G4pqLtrpiO@yr~jBj z|1mDxD*P@pQkQF02Jdy+lbbl^HDr?n=aLob6(K7N&(B9CI z>;yyC+}>5fHnr$p6P~PL+ZU{|X9Agl{<$79vd+PO;hLV$~i=43fbSfdx&COjE z^((QJwztq(B&Ou35;k|8QZlXLV9v7NGtpEJqXXM4ZAF>JqK}XB*j*`$#4HrO zg*5sd_vr>%Wd7q2_~SK5F`Q39MPfm|f3Kt)WZ3R{u?@?cus258?QfExm$F+hd>Qz4 zIx3!m1?YST9fQQP1D&NtAr?u{#<&9HL=IHbg~kzqdP#eJ+z~O(P=L&Ss9ChvmrxYX z>WFBeia@=;o|%gzK*i!T6mG+`iH}POsxCg(t_@r`fcJ7skscEch^8?JJ)r?uwsvi= zAtre{sc?2!X^se3hZ?$_Lk3=A#&Tu=-b)&TjEl&?t<1oCPI1u2tWDS~N~PV|@zd`- z;dyOcMi(%XiN1PWA#|>2@SeXBep>72!!52m9f0EGKSg`~!_p~ur148gYqbe-dwa2o zRufe?Mu)pHc@}D@JHoyz*n@J;{Tck;Cw~_=SxT#G*oVFgN9(;<>nXwCopQiU4TH8=cn9;{%$!Va8FO^sK+B-d6oZK*DPQuRN-Fm}n?hB^08 zV!qoB*A)Y(%RK;|nZVb(`p4Je^IF)1QMmcDM1=Y%1g#mvP0OWaeme$w7H6EtW$CUF z9NoJxklL_b((93``lPBDjX@AE;`5s=NqS`Y) z+J;tp-voYPoFoPg2~Zt#HRv0hINLb%^g7UX>5p-`LPz&hj8#7a4Yq;0x$;~u*revH z%dWXVwfi>+^)=@e$KAm&eZbgC-!OuZP&0Rp-`>BS<%zE@2Le_am!-v`^q0HnYNY?x6?e%KzJnm3%1dx58n}iMsOoASTv@9?-JB} z-`f#!vuzWQYQJ}KRb=*`fsse+h=H0yW%AH4DQ(T=SWTf~FE^2cw!_-z1EW8}@QTV7@JR4G0yWgaKwnhHe z9!&}WuD!G4i<$ki*91im;P?ML%|d{>9;`5~6^TU{7`Qf9*9kf6w0$A1W?x8Xasea( zYf(cl{pa28gP;S6RI=Vh?T|v%KU;cqH-O+!$Rsr`+`UrZcC_Q>q37i&vVmnbsrR+f zR%uu8E&mSr?e%2qRpo-f%?kk9-{*`3f=~}Uw33MW4k1%J?rb2Z^|OE~bNT63jh(vK zA~?3{Iv|}IZ;rwb&N}`-(}nrL-A_7GYnHD)e_ei41yG;Z@~KE;6-$M4QhezFG1B{+ zC9D!KjU!~`p2>=@omOuAcSED7LMZTjj!gdIX90+to9l|XgZ-P zJ5OK*uRbY{n|-W4jOiC@fDSd9wSXUW&AzxEGSr~7(lo?@mnZ|dhG zWl}J$D33phip(-~B2TNj4c}2(QGk4(Gk10l)fqJyiB-3}qP?Ihi%-^7K6%);DM|XG zb~A%qSY1yxnr09$8EiAt@h+r%>-f7Sh3N*_XT>b=VDmbMH2X~TwO(x%;7zBVnYcST zcjhc)xNJ^7K$&&UlhAOIrx3;;1ZOU+*Khil0tK48ravuo0b^iT1EtwnjoROS<3t&U<0kJu_W#q zH!~Q`PEN-AhiqRyYW_&JJ_6&qoe{WsGk_4&lP-rzl~4kJAfIshIRu3?qb(-qgc-j1U2hjff>If%p>w zW_aX(o5n2{I_2f&SEs6XmA*S~vE82zbfM0kr{^T8$gFFAdf#y!!(OQWYO;^<4>P=c z1V9rUIz51eGtGnwd?p-hL2STcB3{cK#g$V>t(NZ=x=@Us|Av_}#B<@kK1=)X>qn(h zl!`r*1i3BX&x5d9f~gFJEbJ{rD$9S{_!RE;FfdfE4N@4Xlm*cfe*q9< zkzo3;dLg2jTIj3ywmdk$41218a6%^2a)-@?fmO0w*#@z-i?a?%F-njrZkMmlg#@n zp&R(F)Y&0O(}r0HLpiSRPcEA~Y4z&q1E|ld4UN-HWSPL#!8Tm3&UCh~6T+7vN7b0t ze{$$Ew9t?LHVk*m*8MhBi%a|;afb~jmTnI~3Z+U4P;Xay<*0Jw9BKS!+hifJpdhXMe6v`u86Kxori{3eJMVyWZu(BkPt@ zxxi2hk+%=;kaZ{8Up^8n!-rpgKHJ-!b#@kT6=?eQ`(nhq_!eQ}TmF_=OlZIl{+8lJ zY2uT!2$td?u})x~*}r1YIRs?Q+r_rT+!2DrgbZYcalT{e=w)>(dCIAOCf=gPOaq!t zCp>{fVB^9!Nv}ykrDai~U$LKr6n-tsj{%h)8+iq)>CHPZ(Wq&zez8K8?)mIMLTT1n zoA%g0bM3_`6+z#pX=;1KX$ql;{%ad+rOa5{Q6LdWma9KIcy_qkj^%*=ZPRP`cy+i) zvrIjG0Z*=}VjTbo?!f<;uC%u`&<=6ZY!aP}hgw15L=z)~jG6_2d^Az$%haGs`H*NH zvY%YGp)kC`&vl7LGEuBTDsKu{y!U*^Tsy@malX_T3fkYeWFbM>cK1+}^7KwAZJgU8 zV)uZ~)M-Wg0|XZ063$ShMWVh?VMvY~&@P?p@xp4W;lDz9y&Y0;PdkSkF5e}nmMPim zOj9}4!{PD3<-}_$p=hxP;OzaA_ddLnWP4j=&cPG(*vdFd=Gu@B{934a!qtqO7<&T0 zY2($T;lP*M`uDokul-Odfy1uauD2h_D`n3oek0Sz1#@AYv!WoxA4OBHt9J9D0a7d>e|3KAe;s&df zRflvjN<005FFJqEv*JB_&wJ(4(!XP4B zhR_Xb+JMZA6EfK^aqq8=bj|`%3?q8ii4RU~)?*Q#-BU1pS^;quLm2J4GJE~uAa z68>R1#hjVx!NeboY*x6t-TQv z*faeu$_KkanX07F0CrRu1hcp7Zzajs$?+K~y1zKV>%XL{D{jU?e!UJ)NLG(ip?vs{@B`Q)b{9bu z)4k6C&N1B-oOMi!!!m-VyS;G*sZE%2?T{QT=cLLR4ZkoP1Bv2mdMPHWm;IvpvGNY` zaL8F@$3wQf=%);0AqS!5&CQyLip#vvQ4B?P>Avh&kdzsg@M4HQvDRj~oy0Aq+ z$61aKTG)=C{J)2+SHkd;%dTdQl?8!4m{3&||Lbw#HNzo0Zg$*g*EsdEgx*ZuQgp-z zGM2jK`pmc4t!U7Pf1XAW0GInSC>tC50W+;ExLPYAG>Z9VjQ1IwgA+=M_ca>CsCduZ zkIF?^nd4^ycfre|WgO_Nxt?bI12LZ`vrZ(I$Dl571J%=w{}6g2#Oo2Vt|GPAvp!-pGtBzmU6mh zls!Uaq7j!W?dBOX-eHi>@gEF^*ru?_R~H3)#L()wOiXj{GcCdtaYq7>;3QI2rNwVt zKG+YQ-m#eA%R2!+WC4Y`nJmMcse`W>8J`YzeJ4nWs())9opI?~FkuTAi~|=J{{*9i z?J|e#-KqEPDI|V?@skt2y|HmEO^oY;R==r)+|tQr}ea!fUj))Ehe- zWBBrK;Pcm)`C-+Ndv&Iu7~_z-Oc@_ax8x0>ip(C0M}TqVw%az%q2G^~j*4Cq@3v%! zC&e-rMKcCk(a=x``%N|B<6ldj?Kjn$bhUPIUbaie@p-n&OgwWbhtC_HRSow4;ATA1 z*^xf42-PJO(7z>z6FX6p=gxol^p`_u*_g<8+ek z6M-=!r(ZhJ=@J12o#_M8FzvM9wDIXHwS_j=S*A&E_*-WyL|~4s7JVWThUQoLVksqj z&Io-(S7hi%FRhZivF3Y zx+`_&tK^f^2nlLof9_IAf}MRM+Z0(kKu z!?s0hzuN6BxMQrpaMsupam2qNg4J^d^cVDG9N@qAhZGiJy!I(L^Ztub&XsK7x+*-K z5P^1x2z?9fgEAEl4$3Y_FfpS=Tz9yX_X089B{wvOKww{XS!t}>_`W#>Tpn)58-;W= z3DV>q8^~O5$8h9wI8@4{*Qm4XhnJ6f6rBp%r`O z)&xdnb;@xAi>I1X>nz=Dwo$2}ao>NTIe2_1F6Fh4ybzCpYpRl?Ijbno0Hj*1Ah8Yd zTqIeLvc=sCr?Ob;!Y0=I+$0BMv~|Ew+~^@kFuh0+I~x;`TEh0ng5g z|0RfV*GqaCG@`qqi|$;q)9YYtqn+&XN#N#{H;NsfdatCR3Z3^DDu7-!_Bgo5%R8@( zrIM?iy>8yKW9O;fvuu!IaBJbK-fJ&tlonVh;rSl&a2txsk+g&sG!A@z#aYy`HIUlC zMeInP($MI$C7WAR+`whG)uJwkNxw6e>W!2QN9u@i?{SJWN9M|k~RrRm@$^3l59ox zks@Rpu5Iip$(E6Q=Z%m(``CA5$sWRt?b?^Ih3vmO=>6{d`Mv*`J7dg!&U2pU^(^N( z=bn=u@i2du>?|O35pqD>8AB%~a~Q+cTT;ACbPI??W@Eew>;#tgqC+dGkpo_W1`WtPH5or7`W=CbG-EN^p)W#l^(N}#}hbVtmU>$;1nk{{Y|pXF<*t;4>h<@S$F z{!P1a&sTlc#?B!?gZoMykhOLaEpKwO&=`Dp^DVfAgnj2ehRm*mme^i>-*_`1wsxId@&mSmj5DJK8{p+4#VpuIt;-)wtc3 zJ5<&mIJuB6v1ByWSL=RvenHbd!WDTJDwes-458BGnVr z2!J)!@@NrehL{z@h#1Fh28`lfI}lPoiwQ-TBp8J%&(9dx!++##z7zi2CB22MLrWuw zeY;fS^qzBq{Q2!>1+$bB%WF;cN|_(9GDR7e8LrPvm#yy-UnpK#Q?OH>|MGNqDkaMP zft`uciz^!%6Ba*bJAp<_b`z$nK4D%)Ix|FZ;Q9u|VysFegH_J)C(cKU z&V6#o8Swn|?JkC32%vs|&#$-?v|DmEzY-tL_!-GjtktVpK*%Qcbe*NK?q79Y$o#3* z&n)P?pxQuoXOOE78NB0uq)8H;*khbz@j_vsMWS z^+=0mRR7&{-97Y;MA9qHd$hzN4ulYzVGWlMS`>*lHPD%^BSQ0xJQDy$i7)0t0L+rG z&1r!e0x~-c<+i0pCwiyB8~Eo8Fq`6g2KUz7U4l*>gvxcF0-jK7b&gI&_p0f4;8LW@ zS7zQlw*LAZA+^C}!*Vpze=$)kuKX3aHSK0hN)lmLFtIeEB4SX;uQ zQRu-A+!s92bL-oMx1hWixJ17vSPELH;!{eKIU%aXp10)vdmWV_4}U=!`q3E;I`Cht(JHb23ec(A~BN38MiZ zsgmp|$cm%DIxJaz$S-czSD37dqVAMtaE)jR)U1B#fU3N^uR0bya4buG&{J#BM{ng~ zQpR8_CWlTlWPMoUI@@v9YtKLl)`D}IJ@XT1Q-D}!u`DJAc+3l*CU66oJkSf-D>WST zc4UVJu=nUjbK&y0gwNT~j;ucO`A$6foY$v|MY6l8hC!qE&^0@AUuXI`>o=bhpnl&IGX{8KCTX;AM}ethch05&BJrM^<0?)s-WL$>t?`7 zti*o>OjZ`fp31J3BQl=+cw|WCC#TT%iXC04ujK0$I248EjM$;o(jzlGiMPYS*UbG7 z6^YQ<&$J7dL;j%jXJ-S5Fe&|1?6^N%z69;J3ST_=K*cvg`b)9DB}gcm;8?^8htvRW zQ7|mmw}fxX+@ofe$_E-J=au9{bpN`25o>9XnsM1Y5~*pO_o*5W&)&1Iccto_ToG-V9t?5;Bg6KhlNRE2sgnIuvY8hEn{V|l) z+fB$FM<=R(ZS7yS_iY^0NCXD8I~*0XlhRkEI|rg@@KG)sit#YagYYr2SF>qedHbmY zS!3?xD$~K0oPbBkVj?qvWY)E(#oJRcvcvN6NK)j^hRWt6=k=d;TOb&+#_&V^{6C%A z*G2vAk7Czu!4{D>)$jb(%2sA&Dht&Xgpax!tLfeX%(;hA_Q~6<7V}V{qr>a!!;hY` zG98+Vho}6FdGvZyJI%7_CX>{S^H2@z6Z@=*lIv8 z8q3^{lMzAlo>KX+T7|g+?L#}b%sq##nlJs?k}~Mz;s?s_{Sr=tABIaqSLrGMPMROZ zt-)KY2+FXvjRCa>n|M*$VZ*!)p228Sfm6sLYais~g!eNFvm}?T+3W8IQl{WA_x%?A zA!-3o>(Fo$rrI}!^95n5cUaeM31pf)LvZov|Y1c`Fx4{IchrQ=ZHWb_bvP zn4B%xxuN+;GhK{X>??*$_WuYP5<2dTJYLIz%iVypihBCPf|4Pe)I&EA&6c+$WZlMw zZ3z2)&wiiCDuVi_S~i6%&cq`~E42y}YugJ(a95ioT;1VeQHXJ!O5hYg<)=| z!wT}-f(+ZcnH-SE;ap8Y1I&p_{F5b(1Y2$QZN z&?be`pX-!;tJ{0iAJaiK>z~6} zB*jPi2%tm-JIX_JBk>1VfeccfELE~W`dAQdhG-C^IT2{fUz@-5+f@s66$`g+nR3Rw zE>7Ie*&Ywi3UXED61)L+0&`N5Sj~$6p9%~cQCOQ2F;V`B!H)3Kq@}B`xq9qz`^!GG z?09#6#7fk9>o^WxVw)}40!;8m5Pm2$?4$0Q^u7|HZErzyf+;}os5@_u;%8+|ED)Z% zc^)=?)-pY6*5*sGYT0-5ETb!)d=HZQhCWcc!Bm+`iAVkiA)87muAnSr0ZRa(5qd`J z+=V_vqCHn#OW)|rzPh18l~O)u-|zbV%FJQ5GHX$(r{p7BGl=0_qqudI+1Y)gjr_;h zJNJ0f9>xWnu^^1Y@p4#vo{sDT(`$)2rVKQl(|npAG-MvCh6-lCEyOvle$%*Cx6$&@ zc)>(aS?Gsl#vAa4rW=*ozo?-5wC6+lS=_-yM`2PW94~r(1V?nt=MEErS)lT>f3{DG zvUCUMJWM163-=25*vy`if7IckQUNsQXpR2|WZgl1Pq3`$$szpMY<{GMCI&i1t#Iq* z70)>?ZPR4pHQlUpx`%H6Pk zUB%qeGOE=wcjHB@F?XFj=E=u&QeC~OkWSj*sjNacw#k4G_rB(}`wxw&{=99i{;!pZG z>19-d3#P^=XyWshb2ov}(yehW&Bmsf<4Hcqesf`-;&cB4>3zevset#fC5$H|rE$+| zTiE8S5~`LAxOueH%B(Pj!wfeJT>ewC`dDyWMNq+o)8%X7Qo>f?$AgFpJ)N@`%?yNF zqLj`2z_Q$bZr_8yJ7h$EM2X))oE#@Qfn9Md@<8_g6B_^LCdj)IZdwo=Uk%m2~}Acu9bxsv%MUd5Nrtk5jG53bs4UU^ku z7E>-PEbLt9wclsR-H`K;eYZ!0m)o`?c+)vIv1NQ%$Z%v@bK?EHvN{VX>p&2H@PTej z0%;^Dw^wdkqIlmAYNQ*m!y@*z1T~%1`X$?9B7$+c<#FxWxqrMhObA**R_^9ZDeZ|M zxzimVvRSjEblCTKP$Q8UwYacs9BT9pIcAWf5Eu19@C0!&Y%Xf3t%Y9`O=7V#+Y2+* z3n?|QH6^i<0#=EVdf?i>RO&R>^{;9!M%5m4jO;_LAW^uKgs%PaS9pDya&O7`5&6r`+bnDN5p^~%@mTzD$h5Dd8`s1DU>8M4Lj@-t z-3K=G!_HY_nD1{*L7d3ptqAV5ekUiuRS8>uoO%@|VFK61Fg#rJukwmg8in{HxBqNy zEC#!22c(Ig6#KhX(pDqAjA}SWZvv;veutob{-CkQjMBzkc#@f%Ki7=|FZ%n~b&!5`4t zFa89OVHG;Ew(RCCCr>`-Tf-M0r(Q}JAsN-ibDaYM3*BIjd_T_fYcYgHrSZ(MyK9|H zHs|@U5-afG9pEc=l;{-R`KkP~fAme6;L%r~2aV57Y!bBu`Tbo4{f`Y-&#$ra((nE{ z{7<$&1b=1eTuOww8}1D*$yJZicTn2pM@{Q@^MV9Ea0qsdBmNgk_`$w^v9uGT|4(?4YBe;=d= zt(2)-ND`#LBVc&_#i)5CpT5ZrckstAK1)KM3Qf{m{IaW$xk{kU zqLT(9V>!!q(SW`Y*!`DJI1MzFL#{(WGa9%&k$LG6T=Y>a^S2AkGDEn^$gIMn*v`7~ z^Q`qxuO~J^X~46pW8L3c`vc71QeT~@^Z8ap1ww1hVzyvwhTFd)d`UZ$LEa<2g81$D z8%tV7cSu`tYNI2PQSr$AiIBZ22|o2&+wk?(E9 z((#{Vdzh4RG9YHOG)x}O`wPlE4pm{H`BtPz@2kt)558*#=DllImnK~3y(j4L+{;Qv zaFTW^?MhGjFitkQ=v3WC)NHl{C-Y(MD@J=41IIdVg)z=pcKUvVZ+V&%3eWGmb za~V9TxVW$z=n;{=(353*Oq^ayxEpEPlI9gZ&38~0*i+152nFnv*<&y%@pPl+ltxGh zKfaMa3*n{BrHc{r5)P3>*tJSpQ=fn~R-tnzACwEnyzEJcQDNz|zVhp3J*aAfvHaD_ zAci|1yz@mzS9zr!KqXe%fnU2vQ0m(W*>!;OawMoIHAWn->xM`CFad7>0~tX^rY+oK zTt7y8R;&iY%v8BpY-;!LOfCcM4fx3)=w5jvu#vGJ-M+{S)LpgmjxKmF(Z1Y$|N9j) zUrYP6`hMu7i=c*naCRK7a&;oz4_7hTnIbt+=U0HAiftWC>M3_zZsyJ0ZOOlNrC5|S zz10p7_$I6=>IsYAnI=+v!M>8Q3;l`ceENxWNq2Bsf@GmpjBT_lC(U7vDYu$ZOMch9 z{!||V{}iH6L%w>B!})87Pvk9O>(c;qEo2jJ21c!;#^Fn=@L1rd^Xtq7{T#+DXlII| zQRfRQM}yUCx6HUKGoEWDd)|>}!s}VAmzFy6oVEX2ZlYmahzeG<(^|AZIrr8i{*qGb zLCB}87lkmq=>ayT(^8CzKdk_;3HO$W8wbU`eZ$==M$`ve!WLPhWPEhT7N2<4o%T&F zVv-VBnKXg{4w0#vHA3j#v-$%#)~RFNDho39dlp6=LXe&VL|4xR*e0r+!H=y*j#goB z#4R?Xef!m`Pz6)21w?F4yKB`<1k>D-dI*>j6~c-|etWeI>#@$w$aBOTl*|59nF9hF zXpQpGO%q{kY=igZ->P=K90;bwPo?lA%D#> z=3ag@NGaM94}4Uf6ln={5a*48R@?<&5%y)46LD0F_Rng06k|8>aVk<_88x(IP{jLw zydA#!FeDBz0SxQg;C0V0wBgdBx#BuE`$%M3pE>;pV;k;!RAV@L)n)BEAg{~FQVh%W zrNqhBWR5xuT3)f|LI1>tINr}LQi04yKeN;n;96MDqZ|=bAk?zNow5UGljwCa;b63G zIv=+JesIm&J#yAGlj)00*L655;(BSK{cU^mymJ6bzcplN1E7G8rDh@3tH-2n4#P0@ zQKyxpzTekihG+b}^ic34n7y7~N|l<;J6!PU|7rm$Px%XDb%os+7&~WH9!%rUZE{=) z@xH5d=2IubTdI2<7n6LBSW7dF=3bos`5KLSfjM;ME^NB8=*Sr#DwO*%PyDfIu_SeI zdDprGFVMmnI@<@Y_Z%32i#pf`P&Npg!`BME^ zm`b`}B=EGI7BBi#)j-`cDPgl@&4Y_#HJBK7r1gbE*Xf z1@rRg_X%Nx#S!-(+1NYikFU-s<#cfV=KUl1^F7k=p(o+KOn%<<#lvxRuJ5fmR+&Pt zrKLVdGZ$3A>7^#R^F9!iQS0%bE9||jPJH^lp8IM;ekhAk03|4cvo^g?ocXLdVnkP% z3q+QS@-SFPG&9O6hYyrn!!t}3BD+P-rmaC|PEDM@!i(=Zw#o9PrBcwza(_|*itD}} z;6OB@FmG=5`xYl-TrU%5mB%@OdD(L>DkdP<-RX=sd z`p8A8cf#x!rL4e@hIgMzPh)wG^hqmWh|SRB^+#ASPSVRSDnP|LfXmnWbEf`F@ug23 zsw8pkPi+i$v{suKEG+&H3z1#S7zYb``=3FgFK*nKqm_n}YHltR-*>W+8mFoRAP*1a z*)UQ3O7znQ+P}JOm=(KLgz9}Lp1Eza3MHi=e>$Mt{_eW@9ju?uu!H&49TUMm0>4p- ze2N9S8L9>?lf(m{@a8^_Gr1Zv*xxj9TVd>9ug!V_PlQt%jBB<--VoU`XX>prb(DC} zXyhp@2fw?3?+o?Sw7n==)o}VO3Y6j zzkWpL^NHBv_}2sPFLKmqD$Cg<+&OgO@^S4mj}@iqPaI`9?)g|n{nbl}>($P&DI7|N_y?(9pVQmiY%3^=RMW*mxmD(s;tJNcpVw8kR_ijkDan-H_p$w zvBn51-k^SPLDj!lTlH~5n>i}ME<*jwYhEth=CQ})6OH(lcT3%0*K5u|AwNZ9P(Zw5^V-taLPe{Gk=7-C z-3S_{k+|Im%(DL3X^$wD*a~h!w)pjaNA8bOG8Mp4EXVr_Kpuf^=fvx+!eZuaD!|BT zmAKY5!eWsFy443c1n{H9arIz6F@xDIQprc==Q_a%<>(xlY6&jvGqA@8M@$poW`y#U zk=5~#OSkTmREZJn`FgD+S!q1GK`wb|z@;9u^EEFyWjsBc;w)>Drk#GQwhp%V z82&UIOLrKL7{v*p+u4^52d%0EVVRrl-gSCn&9?2hZ;9jSGFSl~R;r;5*POhsEIqpy z^P9EbgVsWFyXO6iMa<)DHDxoj*tryQ7>oj63GBT^1@fKHUbpyB1z6xD)lG%-m{e~t zNR9UBq?y_EhcJ6%V*)U$uh!BPlkXeggVMY8R+jYy?D7=e7-MLbf$U4C!Z6bh}9gL>_SrdHBtmYJ0oF!<&+ops(xJJ~u=k^|Am z-q&PgWUXmqWjyeGuCEV}Rk^YUoaIWOrM>byhzbFr*71ntDSLwD#7v5PLLqS@ls_QBibzZQo|7 zJ`>7~f1sh()BvTE|C+U;_jgG zN8`jVz82n1X8I8+$C1*2|L7>|cgJCz4I!O-CA2p+9Bzn~CH9J`2id^hf|Ts$krdeF zw=@<7(^v{@K(R7LB$qUbR;C?;*8*&!w_^Izr$JZEwQN=8c@?LLms*9I*8SB*(9d_0 zzMB(LdwUJWvmI<~Vy`(H7}~6AFx96y7``kkTNn}h7pbR(VAs;q&*^Gj>B!RLc6ci1 zo8G>4=CN|qV^8BB7X44>;70(avAD{##A6H{`|{X24=b4T1nEW1QTqL~c)fx3Vca)t zNNI{u!SqL8TJ)kWx|L#?8@oD?n8rg2Z$6AK@-p7?bLgqJ#u=H*06#(U1IY@G_)eWpnREVNl;?HUwUmE=QbI& zc8LWhbgc$_v5`P$`LD%Fm0>}Zk&JN0_O=!vdplpz<9R*PbIqqA%~EGf3*!5Ll)DCN zxxu<+#`oh@q-MvJ`wkqKGn@y6M4@mNYPhwu_YHVEX21@F(@NpjLEN{Z5NR6idcf>~ zXiAMV_AKoj(rIc4caNR5A#>vWq}y*lIs{)*h6$acMnAE)d4!a=`SFdLy6Khug5(!A z->agqUg*>e+y_y1`Lb}|Msvv`mZUBD=Ra&ORub@>o&p#Uh29*We`UIKhzPSk08oKJlqD|02OJa|Et# zrQ}l}Q5c)q*NRmtxD%fFUe~WgI#wxB#q)SJYd^NLK-nedibx(JFI%tC+#*j=?MuD* z8~a$t7jg%dx@YdV&VH=s%pG;)h*0j;`}6*E@xh?VgHp}%WwmcTN?Gb%G*-8`5&wn~ z4()G%k?U*gRQ4w0tgm^wU?5hRdEMxlacAbK-YQg{xgt`2P~|p1$9JLihezMm8eNJF z8`3bn^V>o0Q7Ut{L45|K>INckYk3B80-prPNtw0f;%#yU-LO)dr{@zoH$GyDI!C4gd+;%9=bVyR|8-2i7!9tAv%CEPN`CjGRIA~G|NrOdh&*Ab^ zu*fvlo}?o4B90_PMlsL8v|XYS)SOI?KRBIvkOx3-Sm;5`UB>ma(j*sQ$12FMq$uC+ z!&}AyNs{EkJHdZ#A~4g%Lt^p`kO&zhJi1UCa8e|llLD)aFYgy{_78=SJK;(WA~4w6 z930Jpjc0*Y@#S@cG{GS23BH$^+El=x1;L3uw>se+Xg|;g&OKjq6o>T)h>5=7ai_Ry z@!nvjR#gfwD4>>@x4`p-p?*K&eE!1#8rb0XtM_QeQZHV?Y>>^ zVGU~&iNtzC4JxQ~SR_AIn9qqO43;rtXTnwfO3H9>ePRA<lk+Cv&0|4H;<-Dz9 z)=Y4EB_Qvqc~gtwNE4tM!A0|P5J!KswU1R;`yhQfXk;%>B!{UvI35<#ueI6MyZ+Kt zNUEb6$h&AO_@WOuTZvoD8OCBWE`C{2xQxh1JU?eohZ51h=V>E!28PkU^o0@YK!0>Q zk*5b*EBa~eAoQJvqy@Ec@$SCGK)q1HatwX|AI@(%&JVO=9@0+WJTqvjfeF{UY=eT_ z#B{C;;)8ypIPcZDZ`>Utp4ikrVdy8X&^Rva?fWwDkPz7{*4pZka2_CIqQC+V$vu=Y&K>g zuole{aq5iOj7FLf>E&V`HFex%_$glf*g!x#YIi3n& zGpjC0A>0>P2c+H(ovj6^6zS=MyQ^oMwR5Y1WuwpNsnpt(u)B?c8p(%>ZXWm>G9TpE zY3M>wSEhiyh?<%rdP^-&goz}s{MfN5eFS;skSBS__n^tVM3Xig8fe2cYQ{*?1%Gmx5{ z-!Y5}3lH?BvOK>+QS^)VU@-C@eJ!j2dUUzeDcd<&*AKK*$G>0zxM9=7b7f- zYFV2vh(3Bdv|)7=_h9)^VsusR03%j2`2mHu44en4%>DhOWx#TFw1^PX-@mPl>@%K@ z!!O0P&)>`R`A08Nr55(WJSEfBK!5<_X9{8mOqK7N&XXjo(5AeTe&_v#ouU0qLUjrkAVct&6!`}=gfLA{EK5>rdP+t{ObY;>XB^GB zW{#5Mz0o`!-!xX{33ltHtee>6-C}bJdrh6n6XVhcdC&c}ZM6IFiZ7`1aMtCm9xMKYN3uIuFq2Q|}w zj`S>x9=JFD&{jYM&7`hM7N=uw;a0Sr$xR(bW^Q*N$5*5G^_21RqSm@U5Y zb*G$xP)`;_Fapi+8?4@V@RHw*D2&09AYs(|ngOqTNj&wc@nhAN3ZVCUGK{{Nrn|ZO zqMq&nMr&+g)sP{cCW9WbLNa^ttw67nD1B0d|dgAYqp1kbo(%+J&|eeaiALf@J( zk2GSy8_ZtLYoV#*TCAKr2vzmXJeH$yXs6J9D7k{6Sfo2Fq*PTfNm*+~9RCSbG$UIr zH?}hluXt5<#2U2O2|l%_2$+;Dj0r;bY3TU~=nGkV`w*Pex9!l=gjt&pYH1quAKtGL zQ2I)Olvs{S@5n&|I|XNg_Uy>~;M6jJ5OR_Eupdd{hdIHabyyu7O~%dv$vqFVXWh_u z?QQP}dP(=uv$rphn>%npFuc{iE7|)F($_!S>~pmzFzCB|nbZH4`2pz3ZxCA$h{kX( zqHmzSllyP!4YDp|svHE>OP3%sqx_ArKkFXkJNN%V?$w?_lJ!iMByi$8Mc;~Z#%eY!o;dq3Z!_M0Sn6grUXy=@F3`Obsy zb@BI%2)Zk`b+DSnde1wU4s7AKs7@DtZ|2%T%rwd!G`k#qf;~LT@z`+GLui)?d0e_M zt{oRVUeJqW5c6A!ar^ORU+f10fEadHyr3$g8nRH%bzu5y&+oWV#`QN1H{+-4W{ug= zv?irSk{)w5Rlu?3@T>1b|E~-o5(Z1#BUbG(Jkgon^VI-H3s6i};5M8@>{npmb++Fm zeI9J|Uwr*G9|#&`tJL&*aK zKyMsmeR5dnz1p2NKL(q7hH!}j3rnJjr*Hnaep+=3`2b^j{G9ylXJGR zJcPacH?kNKS}`J{$Ckj|{z!kc#3sDrq+|^c!sG>p|2c*ry8vu`(D%p6qBnwNKTT;C z#vvNR+4!O)`@xq8$iu?nEn`zS1tM&1>esx1vPX#VOX{px`Php!_V#E}dz&m?D_ko8 zDY13ve-(-S><&7DO8WQZofO%cYIU-!Ix%{i*=0!yWIG{1RT?vs*|lm91-#Z)3RoT^ z?)~}Q^O(Lvnb#yx%uHCN?LrR019w7Za-Y+%Dfr-Z<>yMuH&xc_$9@tQG#a{JqkYxT zy&}=P;cF?ZUt0mqV0g>Ph&lDXd8t+!{2Z$-oA2yw4?Uix1j@h`XWSuyHq+om7fXdQvDZn4<>Fcbe^!u(+T9m z(Z)4!lA8}_KJCC2O=wP0cX6Vd9cBP;L0<5xO%bQ$d)i^@J+3_8kxys6{6y1Z)!dx0 zn$Os~De1BK|LKwvAEpEwZGIE^kgK%JviDo_1K()_pGli->?Kbb(wC%In{^Yth3cJ6{@m1ZJHSiwy1FfLxy7<$me=Qe&tG^qNln|VAXbuHEOIK5^x$=7}$_87LmkE*<~*ydcLgRVQsw&SZ9aA!Ru0vvGK?zckIpY0A9r-cax?&W#1TX|0;oOM%?Xvsi%7e_zCb)qtQD}1ey-!GuQ|xw(`$CIW3k1 z#n|U^M6I+Q%SDcvpue->c3ZxqGb`4=9S0ewmzXMb@l%}_N1Kb}#jRyp{nzzNlZFxH zYOvAOlA?{JO-ASpE+OcwMz1Nu!ubk7P$iXha(idjPG$m_&zEOv42BBw=d(K3hFc&>LlKecc&r5#x2}@et zcJ07=X>NN0P@)$Wu3^7vF)98vkKJ=V7}}6Wuo-Q*B~Tg^t#aMCoeGqb(9(Kv_3Z=R z8@HP--of4Dq%`}aQgY)1{kva0&y(y|o~Q9%cEPu-BlsIW_l?SaUvfOpZ#f=mfYr4a zcAsAs`TQi3&@aBb!RsKC>~oQ1nG8*dv433rWGVJKM(m}#ooo=ZDaw-DbrCiMuYh*C zhqk}K9(fBrdUp3>TTp2?bVZy9HPNjci__WjNaZ0 z+L_EG_{s&Nm|A7DZa?*Pp7sVF>WrsY&7JSf8^i$%U7FLhg z3(IZn?V0R#N~XQGA6ePOv_rOGwqYeCD-~rkU)^!|$|_C{yZ)>n#3AGnA*18CC(nQt zI2x<;JO~>BLOsYo=B8-k8-IS_x}egxD>5P(7S5Ef=WY+T-NMX@qq9o{Wo#6$a?RAUtQRx`q@!$kfAFxL325AmnbcXh@1dtI$$g~#3lJ}dT< zmMyNV453eayBc3Y>l(hveeUxrOV0ik^_L~3o2MwxRhBop*&k7#nHy449IQ?qre&jMb1=Djfq0Hv$MsOeI0rB{;+Pr;VUW zBt_aCt(8ZL{CPGx{xgT>kAF%@iNqiBDVBw!tJZ}a;%WmQMbi}$+9c<{x`IpawKiHj zHLhKWX2Riru(Bo^j-Uy>b=29F{zbfgTF=}0HzoG!wo}L*{8ryq{S|0lHo5KLoLFVF1G8;#RzzAkZMEy?M)^1zUTRf&;$w*`{RIF;>ss`)l+t4{GMLn^ft=vM)X*Rx24k3Mm}(wPEwZ7O-glNQ3eUqnK|$k(a~=*u zv!1J7p|6iusPys`#Ip{c zib!c7?u$gJIy~fT{zonq0NJTUW+sZO1+TF6RAlSD4i^nozAL>{XVI9gm^wc#U0Hof z_ftte#`UFcRt|M3N3kK-!|un2R*EjBE6XKMhqu00y|y)-O#6(#IUonUQ1yI6qSGIV zTqX_MF)a@iuBzQ?j#?&uOx00o+5YQ7??`X7aAw^@_fx#SVBKvM6b(Z9bCtDVqW6Vp z02n4L`^mz`1Vyzp2J5>l7!m5}cOJ$RAGvvE`{E}aXWrurww4q%RQOoZmDH3GKq@Am zsp`fE;B$xP98tML+j{x$MFi~n@Dr|LpH1Z>qbk8n;D^8qqarH&EzQqri0F4uo?h90 z5pg}{(yc<`&o`ja8Iy>ScRc6ta<)LEuV_nwO(X^0FV36>JHuE3=f4FHtR}tcn#i$D zq}UGu(3X2$Jd=d_sRGj;I$DX zSPeJ$<3K~szw>wLrJ(4*b3Zh%OUJrLO$;u zZ?p4<>b76QNns3lQRC=J;nabj>P-Nl8YcHR2%d4xH+hLs4T0MEg zf*-3CYu=bmZ?sz8xjkGPc&nPl0@f2PTnBKbYB{hB;iv+nseuOkPlrZ#TvWLJN>HNc zjv8OHCbaz(x1CUfd8EO#r{T_2NyI4v%QcT+o+lU5i}Wu%WT}0mZ_q6!a^K$%(2lst zam_nFmQO1rXy8(jRe#p$Rvd^w3-TGhmdtKXePe5-aIUhJ5*sg+#M_xRpyhJ7p#yU| zyy*t##gVD>xKmM0aE6&nSSmL!7IXLbAO%hCs)rbFuKqdv_F7Lcu-50>|Kv_aC40}? zm6nj&23!J7Xm3Xu+xxit896wLbitDTLsML)`B;Z1gxNQ>+;jO}#e>p>ARVsP^n=r* z0qw#(lU3$~mE-F}xNj9&yLm8tdz?8Mnyd(Kef8m?gN4PLXCV%KM}FrWnW8GBmVgNiCfYMWF5qoIa;Ir}|KYHFR1A*R2$OBtv9v&wE42hhb0Wlj6$`KmN zA1^D&2CQoSvWvc*cqj zuP#5DxZJ9s$q|X#J5+9*`9=m4@v`q%qJ08#K2zZlLL3pr0_B3cjinaT3H>YvX4wnV zvwc8`0q5Gsskrx0VeFg^F^ATelGxN|X71H?HK(`8i7sE9Z}O`OPfs;0UOEGV;$Y79p8Xo_@OuwUYqvL=OY7z; zC`@aK;^0&r(vx{xWpp?1{9471Rym_!?w~$ll5umpPlZ6_A1v3LD{Yq$YT0PYV`Q)r z08rXZd8eS@C4!WC4?qX3K3-vOeyPV)7uphbC6gA~Jo9%HBWH3GdivHUhr-Qa`8PET zO<(%G3fGwbkx=mSvRmterz+{^#-6V+E^B-Z4$v6TIgJv!_48nSh(O>X7fr1uIG&mTx>()>Kh{p0zM@Nw;M zqV>xo<^;E4xPrY=UO0-slr!~w=c{LOY>b6cGG*;&%sCS68Yz39xdlgcs)yn71ngG_ zeRJ=iGILWFH!P7@A*=_E_`@Ekollz{g7-A%jxt3!q!g>JUQIyCXZ9)KTV+-BRt2Ay z%fW|cdA-2UM*}w`3{@m~67i3ApmQbkTfb!WS&Z%GV4O1z^)z9vPXuE*?I!z&caF(j zR!xdMMR*&!Y!Ou_{H=d%Cm7XOH74DxhBSGc>O;{OYZqpWl(Y8shGx@?g}+Av96FAZ z&r2hpB*%vZhlXCjgw($XoyX4|$r3(nVf|>X^RviducXkJ@#zPtK;_;F99w z>dh~@fP9yl?>eL0--t3S$icb2PsX`b0Z1l%A)CgjVXN-%7eL%t1>myspt=7t>Da|| z9R6*kH)utm!zxA2efV(!p5*^b&L=3My8Qbc<9N+qCooR~Cs?$;D2G5agj{cHggfYF z)w8YD)^uenwmwNX=i;k1U;@eJcwB?LZoBH%4pztj04eRpW$lT@o%G{Pt+ zqBj3dn?W22<-5z;bH$1w(b+6e(~$VZzN;_SAfbR~Oh)odDZ8Ebt2isx$DPW=kvo|( zTT)kE!0?rom2jRPxc)3A0*vj5KDceDGbmt}rh-Z)B> z9$16w?QB;#eW@Meyb#G)OL42p@Y`R}%2z;Kf+D_v-^qE@r+2$fV z@pUcIDO^%fAlt$=qhssv23%=&wuU!7C}L!UsXYo4`1Rp7c73*pGz2%`ZyOZ2eKnF- zlFK-P@ypw}w&1I6I7DA3XX?{2-4tZuy{;rz(Eev?I(B&o_cY&KpVqEAgNxFkPB&{s}L+{Nsc zGoJb$OoK1ApRWbxuO$U)_q#ZD0ja56KRZf68vll+y3WC}tL29={g!tuxClt-DAj%4 z!r|}>c%mc==H%?R@C8OG1IoI;2VqZA3uVuyxiwc-GLGOxN7efpD+m4>HFWSlrJ(TU zjXECjw2Zo=PodH2Nyf^mY)DY`Djk(RCPCz(m(Am@tcu~kFI(TA#+fFdkr$wy2n5wk z4oZ1j);5xKfb;^9;*HSzphFpTaqv+71@Tejs22R2}NTa zON*W1*p011DjAg|3?f+uV>e^ZI@~ zne-0rZ2$UWKF3$rQsq5*iHmm9Z&i-t5xKg=iIszuZtXBfnfInrM-Sm;8Q$CWTy-TO zBkBxJ5EU-2iw!y6o56-F@EG^s&`T8@f5bvd;Cwt%R5ZjYgvg(1y7D$x@OVz8R56WO zY*5BX<$fW70m)Z}EpJ(&6Ni@Q1ZTKei0^}KgH_MtWdmzOUgIT0>dZOv0~e%l+-K$t zfx}`&^&)Si6#{F<41;|>%nJzPa?J)1^>H=E$JnkR8jM$R2^|TZa$7vrX{0-YW_(WS z$>_y;u;kaS9YQ`<0^+pP=(V+N9{NT}#lygMY`fM6I68`<*DYL0iifM2tm%g?>$F%6 zWK6usv22n5YmGI0L7J9GufTcbXvS^7f`hn#GB?3MyUQCf@YA$MHMy0y4!p#_Q9){y z=(iJW9LHp1#Ju zGX3=9#Tr0mn84Xl(CXoxxctyN<4IHchFq8Qc0p*gflzDSZ8>f&^1f*q=wS0A^B#)! zfs{j?5}NrhFFuK8tuB5hFa;A!Kc%B)_XNo@e>N$8alkvGx z)Bdk){trmtR-AO`x)g^rJu#zf<@t5Ka>@&yXb(YTW_4fF()pN$&q zpXF?pxWpoQ?ddyfh;%}-oXQ+6Bbu{v_^SmxRufA`FxvZY6ol+26XuR_U)D|Q<^wQH zEpbXh-=_ocAjr?zeDN9oy|z!Gl#X*WlOq;bvKubuk>k>{ujsB0Ww)o)2*NVrmf@Ew z*Kw*mce~5Dh_kal75xqk6y51O`2vzkp80b8h@UH>`#b8y(StOzQ5k7;nOZlA26Gef zH>?znCD18E1+9-CYHDRvD+w~5tvu8($M8LS;Bbc=gEi^x=%jfv*66C1WeQ5K(n+xU z-7sO#TlTLJ;qxUSe=p#SpZS*s8=mx(BhzZ;|MgLB@94)Z*XX%v3 zEQg5#tbO1+Cr2EX2<~UrmQaT$q)K3DDRBq8xS&VJM+#@mrk%U6hw+Bj3q$W*wS=9o zEwHd5xs*%0Xg!8$;~$pGLbVrEZ)yDfFyclh_SB48@{~50{~`A|LS0>Lpux1wvE%4l z=~Zn3y2RlMs~3XalH4r@lBLIQdF*$Ju6etF+V7-%h3viGsqpOrdY+(Z=Go4uOy=`I z@MV>x2E7GX2~qPzZhudN-B8O$B zQ-b|@-o8E^VkE7)AekIQBFN$IY-w>6;eUj+D zN*!fNO21sQ?ELLX$9$^{maT8Add-*39r2la#)Vp%kK;E7ghZbh;>Vh zOc!B68yWkIp)CLK2oUuobl>v98bQNzQf%alru)bIKRuG)55l5>9cV&jq1Vwz2I};l z=LP#o=}XxC0T3TG#9<9U=D6s1O=gJe1xW~*W6_U^+; zNo;#yM&zCIK}LL^Y+aiNfGf#TDbASow2+MxZtu=!Ad1zwBCe!d&?bgSPG_Qn6HZUB z4ak;s<>C(AczC$CkV&l6wQ64V{eZ)x+so+O0rj9qg1TJiM1zo5&Q>U?_J2G4s+!%X zNO|BL*n#KaGdx3R+WyFHcxLax3)yKVl5F=(*g}Kx4;!NyOgMw&DWRaYa{D0eOEg!J zA0`4wZnkqFcYR1X!-R4JG4xO8N=r*iWK2i1tY3J<)r|^o?_NBku=M!va0jO3UzMwn!Vgq$?qRQVK}G2gV+GQgf!@ZugIZ&rPf{sH|=JhHG?S2`m+ z647{Na^?c>d9F$mNbUDK<7VP1w670ZTs|%O{SBy>?N9Su!&5PaE7n6d31=9wy> zqWN0ylI^+pXaNZhTduDu#o+hs6>0AiqM>4FP62dU*j)@Z>>P-aXwSd2pk_@hxc_Z> ziP*ucEJrBqkyjq>g-^i*g4Xp-D0)QJmQl~RdgZEH+x7Il+?~-G-KWsOkgk__sC0{1 z{cV92uP(bJlZ%yt+y>>ZeIQJt0Vdi?2S(1{3bzj7ta(63Y3-KcD^&S*@f>;@h>l*q z!aKqIn)9hFQqtthTTeuz1hi9DN`z1!#8Gj0X{J%u3o zBp>3bCE*pB@c<+=4eaLn+Z!Pe2(aBo$EFgeZqo>O5JmN@@C@ReHGPscj1){ zu$MZ4Cm%0$ZrdgJE#Z%3C<;Q@6zotmBlirtvp^vpGQdU|Xx!#n#oJUs)8CSs2 z!RHg3pK2FhecjbGF^5DXp{vZ`bI>NdMQ;Fk&7Id#=x{trtpjMApcfgFWtw5S4HVR0 zy)O-t+>gR!`0TeF&aE{9ROPGM$2hGxfAtVPu&rM6y9|LisWOB$Y*soeMzhd zA;0SHN6h#bvy8w*LXDmli}ny}gwgFAVzw!BdO$mjThIJAOP`Sm1OgcEUdTdU{GG0Q z&Nz9pQP$3_%+F|nWn`$o4?2Yi7`5Fpb45IP-VHsOW&g&;RoZbc1$oGi6K->V_3%WW z9$y;rLv52PBl=yCsXuP+0zq(pnoY*R5Z@Ck@$SXX$d^rV>8W8U00fm5zSo7zr}~wS z9#pHI<;nosBu@BRfcvo~_vbL=_CwibdoF99qPJV>J#>ZUSFR{vwW=CQ(`05!pTcm< zS=BlBoYgWe04gNUt|N?^hz3Q?3&Q&x7weT7%+2Fv8AgE%(Zljlq%AbHdtJo}%0 zk@h8VmWU?b;C4UZHwfw}dKAcRhe{!5DHh;HKUn`0-lHhh}YfM|8xzt zz>bpQ+?p9z)fkUlJyWJ${8+3yNTbYr$=BfiIQZ8BMXH6G@pfS!85Y*$n(C2w-lvLp-(RpR%(DZ<4ol+hQfQKW zuPJfbWFTg*oCSCCF+(4|LSH6uoPXB71~W<{->{Spd`Iw5|7y_;LmNqe&3h1?$I!uX zNYI7Gsl>}S?-6;(~rQX_z9SEimPva`>ejQI=p`y`=HC1?zRk;Q1 z)8qL3LbiGF)wgC=m})d)NAjlPpOmp&t_D)q5Ene{_ADxYpD24!rg1tK z3(JtTOqk1iVgSeJmgv_$J;kRT=k!;6O!D{*xVG@X@XG8Jd zZ~jMb(L$ljXmt?~Fh14N!Vxj`>G9_yN$~!pC!!Qsq-3RK#7p<@#6!ec{;-~okP1Ll z#5NRKo_)*S9{s#FqxE8kqd~itWDD$9T?nk(0Kj>4@m^SSID`FQ_rTVT=~#xjtNy%Pom>u^#cZvPa5|2JQJ(41)*0{d0$nxB1>ZV{b3~+ z`yF&T1YIi5^_&_aykdt)%jtriThl4O83ye{SsWyayvag~KPE?AehDdKBF-8ZyPk^}V~-zAm8JS#?D>1wK?zN zQ8sxQrb}8kRp;{hDOgWKSwmtTS`;n*VswuI!`(n~l!5rg;;~D$z^gH_Ef{4oNNJ#a zn_Si2uoc*hG??QS7IciqD#*L8fu=WgkL?V3t-QOFc*$e?amqA4fb z95e2!auKTRu39>DE`jw8$FQVYo7kb25|eJijm~jZ6MvuB7#RnAiySY{ldCbys?}vs z52e`&IL5y|{_RBt^M|yY8!n&JRqt{iJkEQl@jRLnJS8ZZ4CX-6k6<_xZf^AY*Vw75 zv)d|u_;d%`*GnagM6Q&G%ldKw`|z)x{DYeyu{AX{ROM#to~;0`q$EAA>iKp$AbFAN zR#EEr@G2oL4AbgTiKj;2-`o*+uGV)U?fTDN*)!v1wZH7=TtHuTRoxu*H&Y*W?TfqF z|9tg@GB*gh6n_TH$i(H+>tW3&(dr@PvYPD#bx%YmDs1ECO#&0x7%PrcH)Wc6gLRpd zv!&fPFt8c8Tj|)@!1yKP6DXbDf9rw34ixt)s}$jKtG-E0vj`)E(>(SDg9I$vBfMK~Bz96(gS zr*lnq>3*pJa_jN-s!QIBAA5xw9>Shzgr^za{!i+&BSguu509~*@~+tslODGWze;%> z-V=W}x~rw4OrWUedq=^QJnKv`&45Z6vmnKcSQ2IG+HqdO=h~B$MHO{QiMQj6Z1Djl zUZn~Szi;`=H*S1Mi@M!;otXht=m7w~huGO8hZIA5t(7GoSS4l{bd`sFG;UbCG)(B} z>ESWm2rXT=4w;svfssPYdf`%!)|q)>(iMkVFMqy=P_eG3KNT&+!BHe+a_m`!28Y3s z^Bm@PhhwgP*g6ohc&&`mORYz-*iXNMqHTerE2Or&u9chu!&^yvw zqg-APw~=N%X6BBWB+SO5y~^qVB}s1g(~S$y5JVuAGY*kZTiOXA-t^D#jg_tVS_c+0 zUR+`Nh4!}to}6b~Os>x^@GUh|s(7vSo}svZt(dhaNUwDY>tg3hz{Y!;gB6raI}H|K z@^FV#Qv-cVT-hCWeIvaicvmvef6#b49^YVVRNQvLgq7#S+`E*heiuP$CoZ(JJ}c3F zov`oY>H6ul$mhgN>AnwaK(nKGpIRI=SSfhq)_7bnA0`u*FJ?iTYh<>!%`INc*-G1Zqt% z1Ye^k4KWh&78Q+YIG`^r#3PD(V--wyw>=Ueoi+l4;A_CIv^Q6-P53F6v)2wQ&d5+^ zzI^!t930ewmP?y>vgf+aGMx-QS7S&6i^!+AmQE-Oi+sAAq1LI0G&J@MtNs2kEMZcA3`+Zjjbpa7;%K#<2ht z0*t%2oH_I6Ik$AzTwCjobo)oQ@!o?fvFg+Knz7(hy%kkcu)){XqRxig1`X;1PhFiR zJr@Lv)9w4?dxtB#3qFe4d(2y7GEI5}^=g7fV8tMwWS1s!w)A_})Z9f6^4n>N#z9V` zZYgIM0R6`Hy>rsK9FN>4kO^wZq3yB77k4T8fwS2rr9m7EONEzdpNipaG9o{sNr&@g z7p%BI6w`u>Z?y{}qIA{!zF;MM^)i|p;j0F1PDLZfAFX_liqUKuEX7_MwQW0lR0FuF z3W*Os?Y{bc7zVBz?~}Pdb1n0jj5&TjMamIXS#cU7Y?8&cXL4Yab7hammaup>KW}yw z_nIjs6%U$!>GIjx@i8QP0Q(ww;{;AJWVEy8BfQiDUIirxGUmUZ)?&%)Ts>VA!mzs5 zndc4_O>77rTi9m;s8x%F>9OH2<+UE1UZ|0_J_ptK$ZAURL*5LgB9jv`V$gltX5nN- zn7eVMJSK@4E6kRA7HxF&bC^13sGN!SVxL!Be_YV2$+nq{ zHw-6a2p*{Xk2l^xHD*mMW3)a>eVkticF;>&#mc{6dw^T7UWYYPK*cUCChHQ(&5T5! zp3pc~1%~1A4?q~_DQ{nEGGP6#|Km+Rlq>gOsrbLZUG1;73yN4y^NsdiF#wSE)^}WW z*w(w+p0s&z=W$4V$hY=H^xdoK3*TB-)!x^Ly~=1a~@gG1tNnX}iq7{cK$f zCh0aosd>D?JyQcz^q;1;gGp=DUJN%}=pyUGA+U_#ckf(*NgKm&U5rgN_6{1cNz>Ko zgiP0^k8LZ4{UtF$q?c_q@124p@}l`ii`>X~4cn2CiVl=H0Z9nX=f>I9NvG*%a}+`wIaW&w>tCJ;x!zywW~niF@TW>qp>nTAbhPD9d0(`FOA84NO!-!3 z)H~^pscWXW;HMn*Y)r;CFyaw@0JN1)Q0Os`z;sJz3q1sqJA6mV~e4DAbRa@pYx?Tje*8uzd=oI z5-^osuP1w}O6Jqnz3G?zBSi8UlH;R%BEIP3`UJ{c$iaw<`_s7I3sK{y=)oyfV6xzm zuMG~`i6gvlWhz0Ps0^-h4^~Q+1C@jTLT%By5smABu#Z~<14dq6B>I0&_T3`EJ&oWg zg0o3m@N6k636B@dNaq@Fd>WZ2-=td;d}86G@dliY4LfdhbG^@KF$6p2no{FGf)DMR zobrAtX*woL>SrpySt2G?z9He=UFH!}3-)pSFhGZ7sNlQ;&@?vR0`*2q#+h*6)Mnw&r$t`$|V}(08p*+wDqy z3vwdmHbvfks{#GFu37^MDeEMO((p3W`~ynUWb|ft;#{c*ejRJQt-)4~qf~3nd@~&^ zt*l`w(FHBK3hPF+uX6c=ro=d&cFq=c&^(%5sL;gxKfE1?LJWoh24W8vzUL39;~)Q^ znjRGZ`Dgn85O^7!9~BnbcdtXwFTi1{Wd8w$4q}-9_U=2-$JASA&@8{yzY=&E0A8SC z;{S|_JM055QlsNU*3`BLNKp{DApUjzC*<=Vw}Y++yxr2BGzO4pKzIMkzNozcc98eo zKqP1?xx4?OO6Lst0zq`HoaU|v`!OrfG@E||41?SOFIyi8q+5_a4ZZ?`?z{5ukyy}S zj+p)*kNuq6)wU#%D0^#I^X*O$(+yO|->jg974YR$0Od&#iF)_#;QbkaWM84Hee57n z3_H-(KdlACeE#2ja>V47L5u1u2A@%d4MS$^P`FFO(H&0jjPV->oBG;cvUc}`EPtR7 zwn3PSCX3}FX$y1HkOPejL2Ry%ezR&9aGJ`)zOR!6GE=OJL;7{IK`weC7o+GD6)*ay z5`l8si2@KX@FR1R$!L{>i<@Ic%MneLCF_d=;76S;%j?Z5uzzJiKV?dNA~wMDU{z~} zL#213(EugL@u%cLCjA1w26;)isYUczpP397(u(u(YSsF(B`;rg6Z03B2+`*PqiJ#d z-k&t>Q1e4MAZX4d7gDZJwk6v}fG=xh{`x7%vsf_OTHxN*$KS0aWYT5-LVKCHlP*Cb zBq=JP>$36~(vjiT&oUGTfTi`s%9vla-fH68+JPhm9pa=!*;JCk})|6t=! zq0fNArF4%F95U0t>8z6}j~s0;cpj^qAdeILJ+lXY>ou6QZtxUS^<)O5?=%MORq#9S zCB2bB8vmOPs)Apx0yxX%D3gLj1%>TJPyT>hqhO0+j}EX^#jcbwB`C&mOi?)uB0Jxk6&+*2X=*SAy3uXj}eelh9x?j+*2A#qW&yB3(+ zu;(gSnjDoLv}Yo2Qi@x_j!j^ycY2(#^p9bvD%VE@wh@fPS%+gpANfe{A_l4T+ZR^b zqhQD)bor29uKPC5KGAv)k-m0b=(Zz6j>c0X(pih%<+eW4ZUPX4h0h8;=XPk%UtYuG0Mlg_>_Yi8jsgZBT4lw7WO4 zZY=h++fz94#7o8&IkJQcthv|>q9-T8w@m9us*DVR&*^t{`dx-+fGJ)BfNB8GLjUuK z*gj&6x+_k=p15iAEVCLA43hA<%faDn@0<;57Dxp!0>)-&xpiHJ(5Qo!zIo~S*&wXb z*st@w)HA=Qd5gRudL5q>-$mI>JkCrogoA~dg`j~tAJxtGM!(7DfyOd&%3}hH!K)h zoiLRsL>?qLi(4<))NFoKiOy8Ck|>K9K%>2#+esH9MFlN&#wu z4l@l6jv$YAlSjs2o)OnyldHSQM?=IdI@>?Nz_AQ<;uE{cCHHXOPzaGoIg#0yn|@ok zecO?NUumdQ-kClqIFMG$N}zK2i=7STo5qnS4t^gNf1MB(Mcfo?lr!6<2|l^o!|=&_ zF)jAZtR|sy=2vfrE{;b#Zwtyw8=&b-4;sA9kC)t~ap#0FRpoT_>74ltozE&X+vbfw zMIquP^<4TJ9hz7ba2)-_Q<~q944TvXk1r8MQ?M&Q=W+FVZasTz#8;KKyR?BMQV+W` zGp9OY-V*a|F^NBZc>4CSG}EClF}7Z1`?W5Tp9$2L0w$d5QKnqv8HHddGv>YX14 z)qbB1-#Pkznpb-mmc5A02*c)Zcc%hQ+!GpZ&EP4cIkE2Zdi7*^uk6JlKW*f=OWB9+ z#I3*cG_my*Vm|mYR&Vwb>|D*$$rPC+s~LQOku<@%==)C>MzFOskpP>%4i(d2^)t zeqmZcMD57a!oAKq_H~|afXxSzz~GYh=huTL#H8_27PxjcGOu)T9Fnqezfe@Ktpw0C zeHJXL5i!nRwf7HBgR|g;A@ysRy{s25PH3WG?rYB`j5q*FHM=wC>E?xmg zLUrCX(bKX$YU)>vO7nwlZF`w!w$QT|XL-3Kp6`Cs-#X6SJ-tL*H9nw-?N-Bh?MwL& zZKRXI>hAm+ecX;Q_>V5m{mQ(0PCETYoz9&8mDl_Q*N7G>YI}R1aMVN$47oVKyN*s4ni4&2; z+bU~bA*19qXF{gG5rq6+w-UHRK&rYnhb8tj7acf?QyEQA5Y4{w|Hx4`mub_k$iUI0SGI)C>O>J_o0#eWA zf6j2i=Enl|+>sRY3oa431~(r^iaa)yNz*O*HWh}i~;Ty z;})-szV}Jy5FVoWd!vxhw64SnJ|f(Bvf?8OBSDlDb=PBxD^AIVxT6qo4;hM!0!0-? zX`~H&hZRve)(u0a{R5c{w8V?A$?1z;2y;uziPq$8>D4GnPPgYhM-(YnHIMULQN2q9 zaRi7pL^xxO4Adlaacn{pYlU!DXbz7xS_~h6>6yzQEyiJpyGF31ahw@MkrMD%Ch?;) zWO`TdJBI8?`hbfYB$sV^y1BWL!?wdVdPHB;HYslU>W;6b?-vPTOgwP3^@KA*w+vJ7 zgpe}QHbAR)kw;~qWhjKQFEWptzYG$AP|)<2ff|H{nWBT|aDwF!woGFG>xqk9|MFQc zHVN}X1b=<9g@c9E!_by?#v?)S1T__!Csy7vxReh-YZIIm29?ba%rrVr{5Y*!!aX6_ zxCAfQmz!T@Mxog+l{W22dUl*x+HQc3j@;V~;ye8C={qnF4|ax+dEWA!vi1C<_mY+M z^rJIGg)sIjs$kMr07A!hOEhC^li@xgg<-X?j=^xcVoCAmrAG-D1Erzz8M4yva#@qI z?2gCi`n(sDmd_~ik(Yuj-|^WrSor#VZ7pUz8Q;a@bK$gCPI+Eo-gef~v9vL#F@Sp~ ztn5$%hGlT^9og6>1Hu-=a1i-m=_hBN9qTr@+cs{q^1_Y2yt)6+x4x@W%_c*jb3pXg6;$;i`pmiS_V14>2Ac|o z53N4hb`V<2DejDM`ug?u!m&z+V}s5K9P+5xXNBvX1D8ETRz^cIhK$mAHjdj2gxH(~ zL3+dM4c9*mw>$)6A}*L{ZFRE_pj;Y($yw^Yg5kb=al}-*X8kTQMK!ACQ7IzD}Sr6GB^YAj|&XZY)=B17v& zdw#*@ijJJoFp+1(A&)(TuH0LJ-C1%&*C?_vcpOjicrD*Os+p1Tz*2#ZweCFn_R?q7%(WY5;rFtGIOn#2e-lMPAgVP ziP+z-XlJiL8W34$GjtnEIocEhQYe#?$+PZc#yuK|+8E)8{WE;U)&p*exI$iHKK(oE zQ*@2W$#?UMbVRr1kM*H2!e8?UGH$ZC=fec_b-VOWED84%ogB8j%uWe2%bjZMJghua zjp|~zRLpxtcImhGdGKN5)88}uTKB8X@8>C}1M@rIJLvW9X$>$oW!3@Z8~b4tw+6Rj z@3?|e+$(<2LU@Wc6&ipwh68QV4&M_0jD`xK1FI1>@YSkz(uvV4KGAN285EUxRs46yrot;iD0l%d1v(=dky(I+dE zmF$SKi=5CA_=UDYb#R0UCxp(mLJs1r8%K0MYDLYIz4HddsHEstsPuuF5@Si!M5Ht% zmrtTK{bgH@8NZYn0FoxYYycQ^Wg{WhbTEv>G{0gQ=3QEJzl1Ag^Dh2>^+P@aCBAoMU zu-86t^k4M?7f&=1w#l6gM*{mzQxUmo7z^BN2VPWU=+MonpxMbxkB=&!(GSGz&08P$ z%M*J(7JU&{m!SwoPRq@jM*6d(*#Jar@kuI*(%m^idG(#n?X7d@;=cMkt8K#TS8SY| z7rm}k$^s;5y@JlW3bJOd?@o{XTEXqCjwnH*x~vJ25YM+TO`hSbZsJTgU`{$k^9@E$6;ZIEC3cqhi@Q zCrq^N1tX#N_vVoM-m$a6?H06JB6 zrDfpP;OVpJM`mN~F8N%qvXWq*ECM^F_1f{V>0Lk2kFpRitZsengs`!nJW~Ta=uJT4 z#fX4{v#d?#m?)Wma90KwuOJaX&XgboFWJ6P-onZ5o~H>}&b}js7FUzG-o&FJ(D0`+ zIKwopNvi2!3#7qwh*kpW6I79Fy)~=XM?RnLY0aILKpFJ(u>>Kh+S`(w;n}h#@lzZf z4d=P|5qB+yGYPNB-^v`jr*ak{$%^6>)s6zkIfDETI=~(B>%>xFqURx^aiCU%HaY>{ zo3miSq4!+}`sIre9p}~1us`65Vyl2v38b5>W(k`<(T9>>trrWB7ci0Df%qw??Aua;E#s6PRKyBIIF@*62vCcuP=V- zgFo5CC3}irKw8U1VbZtb8$6rF$`UtI%1&HLoJoo$_;p{ND6QrCB^p)LxghdW8A(lb z-BWAZUDB5`E-z_{_JSYl>&J^hQ?Fi7h?0u68}RsE{m2vDUIe#VMig)N@o$z~SUBC$ zAkL*Hu7py8szNNGMp>{o!vy1{rFoa_wkONzc7C}dy)i2fJt<(Ig;9aGGol!byd_WELKJz8>rEkdJOk!R#mUp`cq`>GRT)YWYy=2`)=Q1(7eJkcCy;~ zh}lOedp-lhY9KPy?omrnq-mWrR|Mir7T91u(e$Gx(Y!hC6GZO`|5^gwIDzVPsbE`^ z1UQTWZ2;VJ=lrhn4b{hfs|xZ_s~_kN%k6d0E@*J@2Yv6b!(3$j_&2?tau}m2m)$>L z#X+a2HBKN=^|!c{{r&74^3xo%X5LPFJWGfiBF`ORNUV)s^StA2lW&Eagv~Qf112sx zHs0Z7;zVHSq)#_-I6Snrb*`qkPQjNNwkm)b5HJ)pqMmsI2z{RPD!)Uu*K@^D@v+6i zW~hT}3brv;G#eOx!$0t^_!$N^%&Y~o=rh&X7Fp{9Xw)0Nc4P%^QzhTL8v4fjxSK!0 z0NuwmnV*nzl)bydyJj}{NC5jO9UiAUXilP~7~=Z@|Frg5-D+UOP{fb^@>-SeBd~t- zG`=`hVXu^Tcebs07@guyY|VBDvF|YHMMsJ66_6%mDeuW}9d#8Wjw%!`DKmP(NCdvA zPy<-FPDSzzgiXge{EJ~@1Pk8~qZ^Z7T(rF7`j0egl{(&tHtE)BDQ_`;*IPJn-A~2O z++o$>xVR}UipaIOc24%L8|Ef5c4YR=HuY`MCr#sktKF+kY}!w}xwaP}pP*=YB0t{;@{cL3_NLEf@@! zF<{-D+P{DxPygl;wH!&ctna^X-C6TcuYzk0fAVKJbPctg#jZ?t%8fsQ$BzK=i#AZG zKR`f#&V2XRj|$)qLjiIGf8S3nT!JG}y)IQ7e*I(TGWDr!{U0;DbqgDau1Q_6nXh%<(+zN)aOe@_MWF7s{4Gd z2qMtY+5UwSm9&*H_^KSBa_B)G9C9~@vxl~C+W%{4_#N-8lP6TYnQD^rk>9WS{jEE6 z(Y3B(TUGL1+-d7$37!Kpb*sLjl13gUNNZUkZyot-?KO5EuMUfjIm>y#!F z)SB7h-@N=iQ4e=WA8@*yYgv0*I)q2hwK(Ie6)AU(<$c_rj$f|gQ&@syxwOkGx}~7aQ0YHtlsl|K-|cK2CrHa?EYZy=MYo|8Re4Y>@)q++PftaXgPBcTC^)SXp{+8_YD+ zsM~AmMOS7?GWOIO+CQo*I!w#gV9+@Gj|}@KTqKxz%0V0Z04|ORGO%bkCu@3Zv&##+ zw#)>OqPFt4YPuaJek;chgh{I6quoI(86G3V09u;^Jj;k_;_#lMs72pTVkxa_@xOB=tzU~AhIu8zke5^U zv)H*Mbv!$TF18$D!xY_!6ogDTV(J4%^p`RX{iNm!-nTcqADtfma=&K4SI{JwKVe*S;e+?J8d3U2k?vS&owb7yJQ>sl%C;}G zzvy~?H)ifkx|M=L=NCX91}(!aQQB$a-W$!~fBCAN*{n#rfxcbw0#O7u=PX?f)H4wy zJv)S&- z8)I6nwcz`vR4>{~$Tom1Oj9!Eh%p~B>@0-mk0)G4!aK|Mq8n0`xx3Q<8{^D;MR-xd zl5>7%1u#75?to65anhV(cVh;Ezq{G|-%Z1>fl|)BGVHTMV%TM>R%^551%~ zfuwY%%jtpJcnRsfq>blJzt}T(N z8-Y*Oig7uYUz3ld6Pr5X^t=@)>02cugSz&P2wrnDndWK~#w!gwsx&?%Oq7|^3y#u9 zivt-^)5{Z#_fqP=s3^xXJ8a z*)*OkWbT}3`jttj&=}|Pv-yN4V}xFs1{9(&znae*7v=xQ zpo&~*a%{+BnC|A|32Z9oY+(W-?{los6d(@%$sJ)gA3xI#AApHZL) z_Qpnsb;8mLYmZAN0F@J1tKD=C^t?auuOq(_G(&>b%M>Yg*V*R@VQAXdq|oV4u-0yH zvko4pfcsSOQn&1m3i(x0dfi;DKu>0xn-%71%OMovkp7a)(z~-mC-wACOfQyHDC4{& zHEni&PVILJ9L@0Msnxi87enVHxKd%m^UPTus>l2RCN!WR9hP=DvsRLA4QuuXOQ{3% z!8B9vF}+Z4I%5}C$p3Nn4TT#ZdNjbJK91P=74Al@!D#a(vO>uOh$VVq=qtjI&6?+>@AyQhG_eK7!+0o*RkV z4SM_^3F6O8^Yp8bO9AmKv`KbG0@Df?GYFd%&YgRnPQT5)Js!29P`z3XcCg-c5K%xp}_zd5tgk3TGJ$ryHf4X2RD; zest)w9?irS@VQWJnYKBmVS+Je+G&V%^`i4^{KWXY#BMzMwT-@*rhj;$a_x%b#A!?Q z@cYg_qr#>F;r=CsN)xBWmP4BdeHFbY)ZEuwHU*D6QnKS}xb{b`e*6Sd1Uto!5`t+NT$ycjTVM)=B)WC;NCXles7K1ZZQ8CifSv zDE-BL>tgfT157nZ(b0k{jy86^fTymX`Ar|==!FM%4YU0hJ)b#GaDO)@&~1JAU)zeW zg0I|~ohKj+?jb{omoAN)EO~2*ABQwSf@G)43|RjbXB+jM?s*m#xsH!*g1snIILYQH z-pn@2x4mk3j}kv)0Xg|g2s^uFR1qkK^Iixq8aSoL9L4zr6`yH%JZic$Apf2O&QiJg zX^eW4!t0%F$K{aEq&MGe5T>Dhe&-~Yvuq_b|L5*v?8VN<2=36dx~3%$%$wRvyq)Sj z{%vL4{7K-RqNNSRxUi5rl%<^j4ULvN7VWj}nq15NpPkuMXT;U#WM1~u9Nm+ETb?is zU&_Oe=bY#$(+lqlSsX|+B))W(`%W%nj^PxK2e?BUAlI4|B(gYzc9o23?BMLcsDat= zA{#Da*?X32^9L5)1l9)#1IxrGHi#hN6Rd$f#ld2{V1UP6&x7JaBWI^65?XwWtM5C( zr)Of!kh8&LW1z1l%fgv>a9xFB)!2YTMjkXl+e zTcRU6Gy3MB^uk2f#+YNVUUH!s|8+q+sztRZgaHakM!=)UQ4`q81|VYzHhi`KTzJrC z+9N#o5Dkv!aJ1$7=&Q8ezU`dT6On$Z;{j{)fsCtClLy)`_jE{qGbZKGSJ=vBkDi2_ zp{LQ7zVSTk&dukCvn#%|=`h@GJ+;N?{W(KFW%*MT_xLCXsTBDlLlsE8)xvHtD0=qh z<*qO$`%^r=izd#`G`fq(r6%2rRj~tDlpQI(`=a}n{d<{)#K)^ci@(UA2;_6+yLGLun{sCtQ zc{i;8Oo_n}lg(kxoT2OS%hSF;{+w1I7Lox4o;!=RpItKKaJT#A3?Gq6^Mog&sB((4 zf_I(AAFg+2?_I_x^8vXm?h}xSb;nO_E45XE6lLCE`(EpMggP8Y(rO0R{=ro?E8QMPOI!m+ma8&gQQ1|<2eag7C= zWO{M(@JZTjoHkb@e|PD!JeUc-(T)sMV^L$X6>#R&zbExVJeNK9E7*>BS2e-8?gZa% zu?fTBp11sfFM($(KyVH6j*_0GCK(^YJ6fQz0M>S6cYlzzHCyV&cZ z@(=+&98ol3x?aE9e*LWkMY&`1*(8WKx;y^vYJn6q3@h{`QHl0B_e}}xA_B6aGt<>> zems3WGS+n+O)mSC<4XFZr947tLO}I254~8(91CEwcngDys5*_eCNWv>%6!Lz{;0S6 zV@BVGlFK@(ftIpE@bxF;@819t0qwf&bF)F=eJ>38rSNqaWFVBxjdixBQ(1XudFci7 z9jU)L+>IUwZ1|`?20u>TT{P}4PAL8WhCwpSQsx^c(b~Y>L5+nt`;CoA@8fjjguU`Ku9eX*|Hs4448+aD;3fdYPJ;+HYRUHzB9rXoaV+5RpLV?CX{e0aTGV9yt}K)Q!MCp|%;u3{nUw)vXEV{FO~H0qFiO(Kv%*8W z&-@k!b&$_;P=Xf`Zo0lawh!GvNIp{?5Eblt#Oh44RebFc^rZaE+v!F|5< zoaNqubdKN}-GVliXLWQ&D)OkISIi&()*u?A<=+TMY5D!R0$bsf1KlchvNK$4A0`Ri zkser=TeEK^Zyj6@d_=-I7|A8V<^2aTk>_`n6? z#F4Fj6_9>>T}jQ%lgQ0$1HgkKgHAHx?5VQDfrp#p?qc)A{1Y5kOWZ@J)K6LbXTAEc z>+{A|rCeWJ`Cr7HI;*9hEH3OFgnNx2ThFQ7&O4@%o9Y2&isa3BG{P$Yghl_cg#fC~ zVZ%i_E-A(zlo|}mQAnE8%X#f!6H0!5el`|?Q!Pk>kBffgQ>McEU?qjAbt#A?IO%oh zuf7n}fU2rmp0XK;?xS`NqE5pFG3`N$2EWxMZ#3$kdnI2WV|42nO(pOmYMZ@*`QJiK zP>czgwp08eS=|58^(Ej?weSCL`-*nOAZ;pJ$}(durA49Cm@s%tl5IHlT`36}B7{LD z)Lr@zH8SAlR8_6=+|7R?v_xJr@UDvrZ%(L9?~BazJt^TKFc-M}nhRi#+^`HXc_g!5UUC`CzYH+zPvZ#U@2de{$iR^b3U3!3ZtP zIq6B;u^V&pMKX$t*nJOWp0vtMdl-(HmA5W*@8d8q1LNLBt zI^pPHe<&OBHW~aEuU$Y(t(q(%4dm)B=6n-Ea>Kt({wOS9~jKY+BfnO0Zz4rqtacy9Rcs!M* zU9BNOuTx4MNcsqz|8+cHwJwnQt~k4|#H<8II3eKFO5xiQ(WF`27>@2AYsu}Rv{9i( zAD>I(Je*6%T3Cr!Fz?$(0ITstuQ}O|T=2R^@#d@j#bRcAO=_h>`*ZR~-@X)_EkIN! zR$Moxt+P94kP{|(x0;ZCG)?guhHCrHUN#ClhKX&G4rqLv1Gh#D--jL)@p3#{c&Eb6 zuP^`5a7>1tj_ioyu0X>*i`}n$29`jh%Qa9BCz1;}rAgSmA^QM`T6D!x< z{;D~W_i}%M*QW=@w{}qu3zZuFLXaDomb6|LJwu(^hp zw?cop4uCno_9%G@yS}FGYn{=}&9`@#%hADCa@u~%J{4&e$LPd}R&<|pY|ewmLtKOX zjvHLwcaZeK3UfSJ18-;4>D_8GMkEIsWIVcMNf8n!)*t_PQW}Q1-O-!a_VapmAF}yF z{Z?o+*JOyszrn$&7O9UrD(CT*W|Z}1-qq0X9-+v!WinMzN2^(gpB*El99#>~ER>al zRdU-_feABqXrp}Z1$~Bn!hP3i>RUfx$*Yx{*V^kXC*;f}v9>4)DJu(>N+5ue;O7j;AE zU5`csDnN6S7Z!i-AB%>VnTR4w-Gn@+INBw(yfnOaOPGGS5_+fgt!AaRTdukql{x&M z%k{5$Wr(el(1}Qsx}E0OJNG6LQhyBm>UGUKCEU7}ocV_0KXZ7L6X)k#hAg!Z<2ZZ1 z)A;Ggg6U0G2MbD&o(qHTir&?&ZZovFzEHe$e0zpenXIFECT5&5@u(Ar`r0N<5m|E>m->@D@_yHBS7U zes=W*y*6{U52dImL_1!P2KSxWu5|7|ssYWG8T&m5o z1=yPj<-b)*w5~9*^EcKPk}*YT-t!pfdL=h}OCzHtylJ%?=E=<~ad5*zGYiK!?vKFk zq?@z0#>SF@L8h>s#ycWR;U=<6#vi{;H8BM8o}~oHXg3BCIj~TOe$awy0uBq0em=q$*CDEzCunc%`s%x_i zyrgfO?yA52i0Z~jb^MkwX#F<|t!<=ZLt{uwMs7`#KvLut$(be_rnibk@vg>@+u6Mh zatW4n)*atFM)>F%?|e=xXaWT1`bwbn4qC$nE?S`dJA{<La*8@d{5b{OD;EWUr!` zSZljK@Dy0`rFxI}o0tyd_?hdHU0h&wHU5HGrEd!H-J^izn4ao$IyHu1HE z4G?8AWPWSpX_GSho)*W+p=ivkBU5I(f*HTzv|;afS!K(qA&OCo18!8g-XSM+c<{St z%eQ$ZzWE6V7oj08D8QUsYCp_rfqO?CMH_><_VbbTkM1(xKC8oXR-6xS@kn9ImWhpW zsV3|?aa5izy|u4VPdnw_qhyA@Lrf;AhHlaN;>krJeC4Ds-E7$6i84auQ;vDDCLsRt zxJKDA9}$Z8M*_ zQ9$|(Nx(;$Z+QODjK8iF4?YV1X2;AkiwF7wa48M%68pF2BsPi>$@rdp)#!ug%G-4G zJ|KFDjKifSqz+2HoX?rmb%Jqea)WigFx}XJ8bZ4e4SZAs*Da_@7*3JV4~8W!3^ zBRddaBh1r#f6IP2^yuP+gr|mYf!mkjs=__$TzVUJc4X$zf8H+5LXguo9PdhLIfk!Q z)?x11vc4i@{r5MkGtR|#?8$iDEhrszjHm5*I7D29AHbW6H^wse;RA9%^bz}l*Ll5I zD|}ry$YO&PXst!Wc+>(L=w7mJ~Ly*`ckuDJptbz;6T@mX>)5h9(qUXq*zBet)a z7-0pzdq&(qH;*6vuzEo$;AJnhOopx5qu^sb6sM8{N*}E{)@1C?Z1@r6(kwGP=zZ|q z=ln3o1c`H>@)h1sUkp{P8y{!gO1|Z9H+2U|4r#Dz;Ag#M2+1c%fRV%R>cy-6s;&eOYXvxOk@6H>AuU7#Nk9<4z@YUY!ozI*)qxYaLG`JG9>>akhi0(IQ z#!CHoPWw_Nx0>O4nP@;6w!{AWtH0`s-dG3a&JRrG{gZe6rvb40=g0_ipI7p5jg&fOG9r6R>zn#JeR{~e5iu#bPTPV&)6KKe9K&`G zG^pk<`?ooP`y8uMBO%QX)%U4NKfZ)s2TOOu`B9>Qk3c}^rn+cTIZ>6_=ZY1s$!Q&Q z#okbov5ZS^>qdTyiFSSKs$lvBzh$eX)iv0f5I|}tt(0=zA$RAviuq(j96~AIqS7vA zet@rIX3kP9d#dYuQ*Hrv<9t`sH}?2V-^9KK(tUE+E9MlOAO{UDkggp$ zXTJ1;$Z0Umy28qOW0I+x7jj*sSf)Rhq*Ei>oO&-cbN>4S5Kw(X%+kAS0^bY~p43$r zV#p_xtSNEd_A|s-O-VZ3RrwpLfu`9{Zd1;=kx`90`lBe;NB-_$+ox;x*g9{GWQj>i zik{=|l-qiwl|N$ZqCJ6GH-ZseVxaJ&kH9RS?XzlomS%gn54EI-ku4`}hoX4c`5sH8WlQ5j;|$a(lC)Qex}$vx)>oK~`FH5m95lDJrLOm^$1 zu)z~`mUULNLpKg`zSye6r1~fQ$Z4!Bxe4*X#Wp^+IyY>kwrQLB_nh z(T{(Q??7S#-(Ayzu>0C6XOC@ZWY=6fRy*aYR-t#;V2GLV`_-`+;LM~vQHX4ubz)qq-oXP%t_Rv?mEz?jU& ze(ObEIB(n^@wPmqkQ6zPaN6tl>)ArXbLKB+<{4GVDn_o|jnR$kgs+E=!_8pi7cB2| z4;hLra&?)Vs>FP0s{mf99phPpNa8n3g^}V_bued@!4`>J->GVn{n^JIRg$_6E6X%s zic)=`Ptggt?GknE``P&k_I2o;T9?C4oIX=FcE}cm58$Lj3{gZ;3b^M8c7JYlGTDwG z%63Dt9v=({i0`BfVSD2`BU#NPv9}RV8!uM=Nov7wgBiLTJoaqoGaH*7B|krGyzqXL z>RWJDr5kQYz|m9ZHif-SVQLPBImSu+4u>rC zkLMTV^kWZW7(wL=N>0N^|H^NZ}mWd=-Fqo$+vnRl6 znD-4~sGGu5T@e-|z(yKHe6Ug2<$vjzN{xroh48;sXh9xfc}B3gVpFE3H}z5ml5FRW z`qHDGPS`Ttv=d2=&(Ge|sW@ApOTVI1aP1lEz_JmCW2>t0U>v>~zzOWed%w({z1NAv zA;q(Kj*tY{zcMy;Qs&)d9TB`0>MqH?5V5Afp%lT;HShB}C2T!ovDi6!;e5G7-3O3F z1#jqQKxOX^a8`V5NJwi3=rMQZ`|#P@g(_akXAta`4uBa59&D%ZKeW`DZHSBcaVr># zRoCS*-~zje=u@f==`WG2^XNTQ8}tg3GKWAD04NTt1%C2>cc9*=&N1*y&>Xp#1>uGuh8$0L*{Dr`#I@6zvFn~Nw=*k}b+twwtC7aG4m zp}bb;_EX^#0@=QsL;S1__Uu7CDL*rK29>!X;&8&Q5Q*r$p$XYMw(e4zyF=O^Zl&(s z{iwK*vUX4W!WBW8$i>u#g)pIj9{Ou4S=YEw``-+*9aYy|QiVPKKq~Io zkNUX}fZ;KKP~KOi!F|sL+wH=`y&Fl}i-ELrODcFie-BXxbtmuQD}4cGOGigX^L*@k zrGD4DTHHMIy~S0T1_#qKkSSB~R`W9+CzVc_X&p(96V)31t~vGTjn%xsAN^QP5mJD0 ztW)O%41A%d@t=Y7532pW-hGIiX)*vB-=>TXVR|J*tE!IyOjQ#W(|hx1A6AetmGq^F zm5;!5Q}k+&1wrN-b0vg*V4&7I9w`}?N8$D9nUDV?%gWSN&w(V*&Z^KwhgCv4f!xvE zcXy*$qp!KamSCg2W}&xL8WL{_XqiTRJ`9MCb-L!u(=3GH`i4xR0xB(T{RJ6yy_E8I ze$&TBM^G$aC<5-Kem~mvm&VX&L3zb>jW(H;5d)5v!X+S)DIod_(VU>;F(4H;V}`ay z(Vp%?heOg5E|o4t04gEp=K!E)O`36KzLLYtWfD~|9hv4EK>;_WBdC&yx5!Pd8?xpT zl0+$z#vc8iVBw-?tPdc--y^8No3bT9Ptw5DDZ5fegF7cbVib;s9iF4p4*j3Q*Y)zhQ9?}hJhbS znqxQ3tWcy}YN9kdPOUMXh<^;yWk@I4;rJ+2z~4z1oCxu8goq2)LB{NcB1=2Fqt*FL zP_h7eoZT>SIEYve=6X*9T;@kyJ(zPNSkPVPc^w5>8x$rB?~3I;gCnp#SDy*eU;S5h z2&{GReN{)kIfNs0xzO2xe3-tF1}1gGo-xW4j_|`1JA$swGPbpgh?bDt=~g{Bce<9@ zco?qn?g`MBSFp4d1Q&X&FFAz;#;*mFyPFyWHi$?OUy~4PWQYycH0I!hc<*zi_f$ zvhxf4_l9_QGxGUFHrT?owe{>fdg1&+G(9QJ&0Q0A5rGzZ z0_yFnbNaIY&4Ha;5I3!K149+w^F6*>?z8U1inGRIr*$s;sh&#&jJzTbNNKQZQ&I5) zvgA?<=Va=cIbYM!$N*v6>C!|yBA0P!WzKCe={&wUrJF#nA#QYf!Xzb!UX2vBXE9X~ z&lIroCp61$Fsi8!GZG%kww=8atgnatT(`nuEvAc-hAs=lo-=pIN-dofKOY-yrBatg zK-#6s8jDw+JXo1?luJzVOSYF`rNjB~4F_liO}9u=n1f#mEU`(m-y84Q+2wRUt6)w% z3=Ig_@=PB2eayJ$ZamFk5XqoC>s9?LPPhT7P4M^Y(Xv zw92cvuAI@BIA@Q7{2d9g~`jt#@wxE|}9;!Txbl+ePuWuKvywZpuo}q6-zIW*;Jt9H24hcqMz9 zuQAmRoEH`ClZB_MXVz3qU5JftY#j(}ZJog7}f3+2x!fV2MIi@#~I(dM1wJq(t?=L&2Pf{dF-2ceNi21HobWWt@iUkfOeC=2& zT=9(y50A_X*#Wn&Bu732k=CpzMXHZC;UB6?%>BZgUwb!{tvGQl<|Z)9v!_g&qA*d- zRciG&Rp0)63ujoocabB$bQgK4bz4Tl{tQmT68Fl*$IA3#;+`P>f+NySZ(Ytv=m&p8 zDz23I#q0$8x|EuEL`+Uz;8$|U#kbCccIFW|IN2gR=Qbas6R_~M<5yx;@E?=0n4mmu zXPytLEF9c9An-p*yZOxPDMF@0n`uLB!OHJkYoLn5#W~dvr}LLczS?$mKU#(P}-^&J9OohW_v@?okAJ3o~% z9KSOr50j@Nk#*`&%1akX$V!awg^ab_*KB;hU z9L#5Hsw;&aSdCFWoB-+gu+5U`ebrp`(4z>be*mzkv3m#+F>mN%NYYf+80|PG>BQRZ|IMjZ=7P%zK0|Sv{Xo ztnY~xw*M{E=H%ihWgvJ{K&$dEEmvV&kotzt5e;KKt^+`4B~a|jjQYfs3GAl)8>lg+ z#2vWsY0B~;oFin5(uE!GOyz>xt~(rmxEn@oHZ=AVcg`Vx!dee$KHw=BrxYszvdzu) z9h6op0lWh7gRY+6SXVbLbI^J-*8*~<~n8!Xj29=O3p z);d!f-6=#bJ@g#sIbQMX6Em86C(j$gX*p}COkrxKXY60MI`ckjbUIZVdcBtSZ^Ow+ zm!!1S!d<(L!JTRV!Y4W)Xq~g!RDGx4hYDT#x!Z?LP8ONHZ_F*fccQH)Dzf=nCq>F9 zhwhYooPZAe2sjPt?Q9J=6H8ZV=E=PPdA|55WG4SVF1=&8K(u7g^~k(e83GZ%>R(9h zmgR@*d$rZ!=0$d80OJM;&H>4-S3|I!@80ccd}O8d3n7QvId+ykNY!YZDA~dm{qpP7 zUxsCY?M_FmZLfAC12f|2mC%hIbAahD2%2F97}Sv9(`r?v^-EczB8Py^7(mX32MiBL&w{>?H| zd0PVD@v~nYKOL z#(i@)oJY^Pfw%Zdxf+yb(G2z3yUs*fso3W|hX`;c6G*yd0(Xzjvx!=jt|3|}iZ}EA zbTXQ1u+8vb*`5+n?e%IIPhRG|C~LnRa{EZN#F337lEK>(b@^)}&+}e*bidj$?Y)h# z*QZKm;4O3W-1S3dNoKSd)D#+ z_+*U++Cw^3#>DY9+SJv5ES6?4>DfJAM7;+L9c<%7nG#N_&C{x{?@Q4ODyL zEx55dsW*;0$qG`P6Ejle+xj#g)T6x&X^(7jVsD4-`HgcHhypd*)~@1v9ewsbp)%nR zXP7=pZDERhKSIvsrI%+|$)Ia~orfdy+(h!#7GjzhhJmyC?68R321AL#sC4{z2v-%R z-dxM;ZU2Z}rePhSZYPJ8h#4F@2}6rr0b};yw**KT9_>j+$Y+sn@OExqiJZn&3goHG znLbiS9tRwo6mBd&9xf+C=!*dh51lU3|483|0?hRBPYr%W`^2lG%Yg{FO zoO;6O*3)M-Rud${a1^Y3d9w+J566sjT2NeRw%=`;=Ia5UE=m|nZc5 z<$iJRJ1wFo(Lf@mePPjJ$#_|iK7}I5K7m-Ys;a8CWGW>XVAfnAH-2)*Dm?)_GJX!I zKDF4S2?C2yd?J^Os{pyn&7L!iuRE_aCqzp`X#Q}F#Al?K>pEnjNM4Gp(GH3%IFzMb zj>HwY0?KKz4n+y3CV!FA8%n%csU8V26po&VVpzShkj=*aNLFYPhfNt zL>c!9e46Wu#HF8(!$eo+wS6tgI%Enh84nXUY6HsHu7vOtW1DfNs>hdbbAC| zVW<{Jeb!6S5@aC9hWqMFADUkGnfjPJH+-WqV;NHLkeNFQmn=PG>Ln20R})^DaD!~Y zO62eaiK~i0J0;6Rg@#t2ulD`ThD-7u2-BFWV6zC*Hs^W2W3?3rH_=qrff<4JS(07N z5KT$2I&5a1gr79_h6fEqf-a7KV;L?0$8od6-ak5ik%4jk3-1gD?W#D2Ro1*$Z`&*WhF6u#bRv; zk6`>rMTJGU%fBEXcftUPoZamPJ&5q`mT)pPLpZCdJiIUm(S(CzYO}NiSiwJ^LuxJn zL}sM;|Nb0?y@cVrfRF{!!V~@edl>X@af_8i*fRXt2nTX`X`Dsy%Rj)Hi#u|GRZlkn^iQBwQjDXCGpVBC&+Oxj+(HHwRYK zRF`g#ZAHi#RqN?aci*0v4(#_-i5uKdH%>RtVov)s_CJtp|GlLU8-&#Mg$?<_L*n6v zoPloWv}~{WJM-+3>7BFgx#Y}g@v;8qx=;W6Yw&a*`ZwA#A=iSrH+;rfCBWrzoC=}q z9#j2@cfpjS!rvg(D~R{q4x9a4&oE#_hYD1x{jw)gDSE@T%1r0{@BAizp&rJ4Pse*G`(m}OcZ{m3+ttCNDW z;5|zP+~`~2c&AvY=`sN4|J8H(pS3_B?AQ>WU@~{wGS#u9zj(QFMKMs+EP{df46sGR zDq;eCrD9==>rz-d-f6>pxL0WH@UI*pGvsw9(2^8rA z0<-4-Fo&`;4uAO*Ao;0G1B~$q?POMzi6_ss@*T!clWY(SPyJ6mw+ky?2|}(8WM3(r zv> zS$3M@#>&}M#rx@VR?J!id3sh^3t$Ba&&;)@!BXmpPlh?0ck0xsQ8rOZV%KxXwGi{= z{}S(@v^j!z$B+8jM(N%{7r~IHqb9wvZgIDhq#xb&wlf-zorX017~U`~BHf8JmnoSVF6N_N>}ErG|v){ymN zHuCNh@nUCeFLQ>hp3y;B%i~g6Cw8OtP$OC+J#|V-fsOSypdW$&g~pu8ATY}b9cr1( z-M-*xnbnm^6GeaA>w<-afwm@t(v{ThSpkC$Ga&RqINR@sG#tNI5oDm84zQh)3%#N} zioEi#q_5#uWx}O?}696d0A^F7jWTb=?Sa9*==RK<8-*Q}nKp3R=r%=#LVqgIukuSHwZnSPo+KaFB zQp6>>vB-Y3Y7a$L%shOPv8*c`bGfg<2;(~4EVL1?AV?i=i5D#ru+7^e$-N-2~y zRF2utrXwYWlfZ(0qV5al=;54c=&aBVMU;esoRM5!wiBz-{fmcQBY$!QyAP1eb4P}a z)|s>iD_;O$p$a z2-zBnw$xHiNIe_Kv1aqooKnY1==14LDz6r*88o;d)cWf`O3QAB`8RipCFqdNPg*1AfaNjNgMbI^_B6mo8|4?1!){6f$ZsmDxFMqq|4GzR=}7zZ-3Nl+x$ zV4RGueH)ZM)b|x>7Nme>=&AjA^?~0+VKREC^_2kudAh}SA`U{h zj2h%`0{glt&$}GyR+Xom*?OMI#7uBDY9xRAmn=B0yu)7kOYY+?2;!EZ?ecKP8q3l= zi@gPVzaeYYx5&4}_Kxq#?vlpE4WIb?9r*Jhd2sT4j6@RW9iCbG0-y1@2QqY%p-EqO zgSYaSB{husdofP%i^vPH^IZ(mCy{ACFS%kvsheC0rm~v$%CuyFE_a|vM1|ipO`myN zc4ZI-e!a$ZQcl}EfG9cbl+iMP-dd(CM}pxTdZ{wZE9=Sbd?MpBlyC>19>~*5QI6LA z`gt%oJLvV$N0HSV*ki)=suz^8z-E0@IZU(r)s{q7ek=QkW_S88%C#duFXecUN}<+^ zK~&V-fqy*a;9HF}>3<1T_X!204kMk_UG94^(LtemgGU3Yeh&!N(wdg1S+z#hH!5>? ztg&??>sz;ne7w)}jI@T&1x>DJ>S~WNPCvDS zBgu8;l=}`=!P5}==-r9Sh1Jt}+pStuWWC!qj7nM`EN^UWPV+XhKGKvMH-X!b|8L2A zb^T}Oa9%~0dhTv3F5BUFq3{ur9*UavLa@}}3O-rKW#@w_ko+ z2tGQEBto3{_#e`4#1E+An-_98Sl+e-v_wS7V41$Skkp#7IS3RwJ2nDsw=+^=khn;3 z`NbArzAIo- z{fU1mEjl8#-}-3JXynd$kI%V@VPAUX1}j9SO_jgM?fD&#UMP*fy?QZ>#URopa; zkEf)Ts*-h%X6lna6euAI)e}-nt#A`QX{iL=$v`K+A6Aw>3fBD<$MAizbdk4icWEcV z`wWYIy3YFy?!>;Ve}nl6{<*9=SFNxAVh=q{et;F*NKq$uUej;fM5WyPT<>j|cFpfL zkd-Z3yqCe7<-VV)mX5@9{bH^DDmE70T}$)!3c4 zzpB~YX4c-E?L7BU4F=%?huD|1iu%W2m#<1Ubm4KhspX$Fcg2@FS--m$*>)eU37k|U zW$p>+`+X1R8uFs1*zF&ewxi35ZnxTAC{&t@Ktkdw0zn51G zd=Ph)__u2LxFB#vD$xPuQB#3x&0b~BJpikes`T($BEA<+P+vECFb>(48;94+7_N@NcRk7KDO8<@Ux! zKK!WPbJxyzs7Mg6pn@Qqj|SvZx$@Qf_TIK@yi%J>ZTcDUHWyxFNn`=G-`fB1O zKvoG_W@|c~8#4sgOI(`%sxw(YJS#ca5=WM{Vfw!_P9tXMXB|xgvRa7pNLp*Exx+dz z(8Quzd5V2;R=eNaQJyS4cgQ1K=&DmsM&om~>XCuGe-^DC=VETb`GD&}M_yjzlw9u2 z$#d+WTrL47ZgKbeK_L&P>gn$>S=stoPHG##@u=`Uc+tqm@FS|{?fSrGG4sY`K5vNi z&b9GcZ$*n4`_tHX#*F)v1jb{Np+^SQ<3G{&Ww%Pwn4WbN6l80!0ULRO6fg+#+!cOM zoNx-Cahwl{qrC3^24wky4qTv8Y;?3+6#DqUJ*?)tgbSEnBCjo*hLgr+AMrNynATZv zGfOv&e|~0;^uxhucB?c)CVd|V_5*(bEUn)R$IBGb{2*Bk(Kc}eJFSVEenH*Cc)shg zwpPrDbi!S2)A7FNXmd}}r8ea_9n`YdT6B`j23FxZzV;O`q060%)MVt!YubJV0fi>G zc(a(Omjr1BK}RBl40C?kxO_MWMjlJ>wB3fQmq`N>3gHlWw9CKBW;JB+_{wBEm<20V z?$b?KjYtZEGy!?sq<^!mDU639LKnJAe>%MtC8`9mjFcXd?pEE!PX}q+u~)iQ_-Bbb z4-ihP7tdZxPL~4NV$VX}N~B^y<(Na!)LG4H$4Zgs5sPuy>$pZzLY^0->dTO-e-D*gO_TsVlIvplJm^6> zvx&;boazzmn=T)RyaJXBbhq0w^P>RS$4y^?Gh|3p z8AVR8&8S8NCNH2*U1NIu177a%vlCMa5R4so@B4}SL1{pa%l3(%U0ohL5BA>^x)KFf zCTO29JfOGb(yI+TN;k9bHSZrEn^~i__SL`T#mQi6TuWnI#wp!Ynp5ate(QrwUD-CV zUk+!DX5CFYV`41+4mtdZB*xspH<#Hm&u<3}iflSQRRmTeHNDuaPZj1r)Z|Y6Yhi=& zHSVRPGy0o=Q;i3^eWBdXGWXn29$nNQ4|!Sm4ktPUW-RpXP~jCudDJaYnkP@-^EA~Jm*rtRZ|`e zRAlA7^U|^~uA$#77>n!fpNU=l&CTTIA+p6D0&b zS|_4b9ikMLFG&#G3F%Kvd0}0ci$J#>GyX#0`o%Fg?U4RZGbumofU&-d5MEzpY8t@$ z$YG3A;7^)8;7=q&@)!l^Ki7OqQyl7`TxY7U%GWrc&(r#P{D8CQoF@WPT}^*+@3s@x zeAoWw=GKP;>ufO1;`j3^{FZ6DOksHCa!&i@bUGf2UKbMMe6^sOezd>lX2}L8FnPD4 z-H$rGgVR-dyOkD}Zz}&+k18Z<_5|yRxpBe#DUsMemk=wj5YP^G8Zud32bB|-Vqn~G zto`@eksXxdIFi#g=7ll5$)dh-Zdq2|0wg!}96yq2RtpT1%Gx*U{^9Ole^k>`ahtf9_MHgL2^Mz}d#nTlIyr=vx#vciYwim%)fM69b1 z%>$XV?j-2=TH8e}ToSs){zVAPBOtPm@}NXUC3{t+28=e!le!q>;&j6L!+%XAu22rc z4V{m-m_0+jYc>vcA=7C{SQiuRPpnVhnkE-nfk8z`vG6Y1h2Iyl+c&CIf?Jw3m# z#TFYwbx_**BJT9i`%SK6>$^_Y0%0$fMu~+;;6vHymNYh$8ags(4>|VA1h#snSvnOm zm#-D!Zc#7;L=bYPo(_1LKTcCt7Ko@ST2#8@UN^^G5ng#285u?Uz-W;tkY4k#?XoA4 zf3%CE^_obDUuWo2!TkP>Mg>9LHGC<^Bes|38kR1?st4?u5qD;lpp0~zcDuD^XFE+r)A?}HmtP$3u{jPc#A&quN^tb zjydE!+-1Ww#k>aad5#&Qf9%XcUsfCJ_lLw|)WhZ1_BbUF@Y`~jL+IX`#mM2PiU31! zh&3S%$I(F}HIeT+-23qGp>|OmeiJkxl;{yyxf&}v`+Yus{MBqSx#Hg}sptV0Y)D>l z|BTCm_TgA4l2Tzovk!ue?rj-Po<$Zme_UY%w0%&dZzYteZP58$Fy3=H*BR1itzAU$ z;%t;!hnwRk@``u@kfgSUhd8$^3yXlcqFsuV@C6PA4qU^g(d*629l{5bng4W62}T?m z^}sGzSGnO@U}$g-r`17eR#+*U#Jynm3EW%YU5NOQ5mRq#Q+?@d!m6?aIs1#Y2bOrB zI z05xzw4&Vn`Dmp6UM%4cLowW$D!gjL*2B5$shez13!&l!$8wH%5DGSDWAX8Sqj@ zX&{`A5L-%sIIlv48e6O47F`)M2!!^mur;B?5&#v*zZI-@mc>~rlTi6_B}^I^a~JPs zC%G3?>plCvanfc$dFyAuRC70|w6z47&)=z5eWDhC!}si*u(NRxD{A)4B? z9giS+{sS99wQrwhx77kM4xvVCY_O(lRAxNZBb;8ewEL|eE*}~!c_HCAqN51C9+1GpUb!l>68@mvE z8B{w1cj59V5N37%AZFmU;RjOqyE=hybt9A+8*Bu$-U{~rf9&?VlL!Vf3ewAfJrg#+ z$(#$01Rz=QD2dH>eUzh38{w7_Wu=fO>!i_32VPYGdp`giN3sl`!1HX`QshIi$7TjI zc}^mDA3>f$i7wa&RQh@ZySmA6s>jhA$#Q|gU6zkNf3&NELKiaq0;rJi0+<-68CCTZ zs!&Ot>b&LD0%JW9A0yFG+@KFK)wM7WcfXd{n>(_gfdraZ&Ofe50piNQEmEg9s3(Cp4a=&o~U)hGvN`nQ^fS?2#4BBD)fyw6NP6{Lx zlvk@y9vh*U76|B0?QQ;Y3=C5djEF^Zoe+%R2G=1|;T6EoDQS;_Zunlr7xI1zCh$AI zni-)OZJwVK$mXHND%}&B3S9P#ia19E`#_lu zmUVLcFc&Ndykym_ocS2Flz(8LqA4#MueC73Bb)|e=GF26gbc?SR^dv5Wah#Wjb>{8 zdtJ(gyC~=e>KiCN)&Z4B%49(~1$;p3b0T2P;;L`iD1~73x!*sS(3eZDC^}$3R;e7P zi12Jcu+Ki}pwy%ZvNMZ>D+GfExIhQ6fwf^Te#;5L3oEZy7A(34+%eq^!59=k8_fPh zB3YI6DmvsU$oTHrPT`r+wO)-t4>?{vVlM!`kDYn5j3bOB%#dNn;-+Bui z7Q%SQyB2ig!C6_XT+YsaWhIVJOb;F|qll&g2Dj!9?6!A%i6oUtd7q^K%}8C};FI|P`G0xI;AqSk9)1d7tD zsdu5=Fh@fNEcE(bM{DRdKDO5cOD@w-I%v(Wj)1|l+n=rJ3&@12l&b# zK-fD$&TU8~txG3xklAd!dWIJ>OKZ3;&8>P%_vpGOJ!l5+088>2*fRYFXK*0M?dCk! zcIPv>*4S#u|IIWN4wO{hZbRB2kjoQq;pupl*=`c4ot@(;92&g~rjZoiz;sxsYVAnNS)`%Ks3o(Bj2$;mZG2$T&;%98XC zA-~?rX!tdraI{QGq6vLr6A{pzp{!lnC1>t4+c?ivAe>Ioe{55aE%t^uIQ{`n=&3xD z434aio7#%#-O)AiT?+qCmnG-H7Y$HzV;&G{b7Q=jX?p|&DcomRhG%6oH{{IX&#^iR zhXf`j{i7x2EvUOAzu;~OPg4#CWRxJg=Qh&?{{6FCc&py~VM-$yYWSU&6@Uyrx_=$0 zajD*s;7<0YwgMM=rF~g;1OmOFpnxp#ft+*``w?jA4O2HMQ9B;S&=9IJa-aJCO@`NH ztgO7M&e}bwp6h5}hJ)O-dzHO*hLg>0g}J>)(%`Vwr3}d*w_m-V|Ejjxr&O&Mz57|{ z=<8Wa+@1i9!fndJqP^(>cLGX}ILU2$tCO6ppkQI8f=+HcQY5iJn+35D-spWF+O`&9 zs*g|3g1jB{!O{dnfbb>@I+rTI%SDU^_w7c(=}7-@%TMpF?O(5Kbn3dr#Di2p%KbcF z38qt!bAaT2hO<%ge5PkZ*V-m8+iB;6?aSOhyKU_%P`GSf3f$D=h=qZ>5Gv)bFo-0f z)Z^wQM0F(^6R)sYkg*egcH8GoT{rV8dX2v>f0rY&oUg-A8*DSe6bG&wcO*DFBQ>qS zP1k5Zq9X!H8#j(^`7-ydv?x_wr%+WkT0C>U?n6F$l8TNcPsz`)XR<~m64770T5osE zj*qKQT$-%YaUG<*U3!@;|LEu<`_Ve{yv$BwRE%sKS^kwhKsV9zSW^@}D#@$$3$^LD z-q;{GJhefr##>yzyY{kz#JwhY5*v}Ek<2%aysV)4516AqF>sAN`SW!_wF>|u*vTSRt%^ON|o00-cR;bmz=bWuicbJn1v!|s3qj?C! zY;5Ioj1dQSZuPeiGK#g02}(-F?;=mv&t5yEGBg=;3>W_})WYhPs-OXR&;T(cZPfGt`!aW6_{7A1OwLeir}VRobvZ_DHr9YS zsll5$$IsrA)T5vfyyaX(i#{PLtUJ%~UcF!GyZz(>V=}9cTTHXMvet1g!>`orKrgwJ z68K7UP4KdDS*dmcH=rv+NFONEk+65S@i|0<3QFM`F;9Lkc(}hAXrd4uz1G=a*-|vY zE_rjR%&Ht3=SKswn=9sGg(1B~y0q!g9woZ7*C@Ao#myFpSf9=YK+F@j6&YnuSrfgP~rD@ z(3B?qMH-+iyUFO02kf^S^$+AdRiY&=I6Y{=QTTZ<2uVGdI;=((i#|5n(I6CbV z0ORd6LKopIgtXlGgRiIpUK5dp5{++&Q6>=oZPOPg^`oh|Nk>O(8dOMAj=?q1(^;tO z2)YAyj=x=&@W$1!<_ot|)^HZYo0$pSrXftrnpYbo(!Td2HHk&$X#zctu@26hbnHM3JQT1!;-BK_E42PntWJQ}}gvuu>34rd2P+8HCeuV^CMt-!=2(_&!uDjv$-EmHy8W`a2A^GU4CX!Dhu zw+H=fQPmBEnb#>JH}}8Gf9*va$V%n|t1pDb>+IV(N`u=4C2A#`4R8|R`SHe>ercaZ1L_kjgbf+yrij;eWvq+rj3;E{Q=g^od0zknPxQ8XdSAzdB z1C+U4p=D#^H;(Jd_ZCQ933~eU;*k64Bav55I%?0o7unDiJNfLHeOsJ|%N>*iwhe#E zT7cmV9b%ck0;or7pB{cLXK-6gXmc1P?b2%FPwq!EpIY&-+l^ zi7n7ZEx6wvt3ae1S+{URTcR{a0vJKJ58OSUdB}LzK-lGkkncYV-^}QevNLX~&;3JH z|2ev$+WKgD+&Dp1yu#}u0)9b6!47qcUK5ZG2P{h(yk`!84I#F-i6?Q#k4ut#_eDqZ z_-J46=ZYE<5NW%ko@4eX-8tEjpqzUATV6~gJ`Q@rc-pm+w-OQu~72I)%I|59)i zG^-`b#XYk_v?5vta#(Hn-~>C{ohm8FOI+zWd<=U)$$H zvMRUlcs~8N*u|7*OI5;os*mHI>nMq5f|tk?3rsh^rYLVhxa|h~fCGw_Eszur-8L0K z;Rxxv=(?I$$yE`(`rxIXqgZ!U6zc!TIQ5f{lUpLhRYFF~BTL4j>D_N)kN!Tua*lNO;ny{=d$;f9!=u>lkXBoS z@qDzowNw~%(>W!~b1wqy^k@rIfU`R@C{#zn(f%RIqcxz9xBDpNM1YU#J}S*em1nPL zbZcCVs5KrTSAJ95!@%(0#ND7;>08+pbCfRnA8;HG(Kf>u6^mjlXE$lC$@Kqp6eoS zv6Lm-NR+9lZ_mWKXkR}$8RNco;)AXLR7+xvD{Xb za8>p}ktO>X%UHs_EfhIZ3CZ9_62l1LSi32XEF;8(u^tSDkr=Z7&Ys@;G*>;>K@#?`KxE%j%LprpQVtOm> z#O23b5j$3dUF%-CIkJB6s!(|D>RlUdWZbisym~ZYm)M0Bd#<0^0PgNNj)yAtH7NPY zJ^bg*@h9$*l0)NB?Y=H^RN3~x44bm{;oHO}v9p`g@4u1=Xdmt`9fGEO*j4~rzM>O9 z&WVe>ukrC7(&le02K$*RfHGIyG3}<=w`zf!xcTYftz8hehnyGlJYc=yVbC|JDstD} zLXVr@o%$H+(UcD#de^$`9(bP?f869V!AMVOMr&9J!bh)||I)ubWQWzr^Z>>EgqWIg zS8M*{$%vsYJ(rk{F6&QG#4Z@8VDmnqFse}PFk3u-zT@?YJReW%lW2<7HV2Gsc=+a^ znSbqi-qkGu8mhC!Qj8v@NOetD_Ay1dCa~U`s58Kt9fF)b+qM;NrJvU}$+TB6yVMFQ zHrm&M$-a0wuXD*M&0QO#j}2afjh__Lv8%wANQ>}|^gZA-)+%78zUJHxG{SDi7?$V= z%bQ>S>QIg6X{7RNPj*@mtLOA9I*3DEYTt0d-C)v(*I z_jlu2>rrTvh|;pB{-NuiZ}RZy9weY#hbyiL?JKOxKJF9ZoK6dAk;3y-^O+(9orB$w z*VanwUtzPn&RjX8ag=0zl^ndc8R+bTUSOs0OxZ3x^}N$R>+%aN(?&?^!W=5KDWS7N zc$L(>ieO`*&5`%nNUCqM-~?m78@s)t0~&6q!}ErQwK|}5tu83wQ7OPU!_bL;9xEEOU563gs zSS`;l>-gA%%Ua_{smwGboWGeKSn}59%4XgLJWbt9ch-@}G5!YG+;jS^|XKrRTUuRnE7c_Yg-fIiro=$n*4Cq`TGG+ra_8v4! zG^$cxAM5xgafel|rOYZT3E1N%N7I+0TK_%=xzR^M);0qke8F~&S4&`|da^?@@w}jB zc?0cx0|frP8_ zswcLlJ0aSGOsw)?jEhsM+7#z^_XRDp))!$U;PfX z#}^VP-dO*lgAAdadB_EETlQ8mdyiLQ^a_{YV!Z}Ww*FDk#<@cf*p zvN3ZnTejltP)#I$Fuc`;5T?0wKaEla-(NtpeSF(K29pocw80M;x zJj>4a%SSP}+Y(i6?w(3-a$5moUtvVE5qAPX=M|Fw5IJ3d2XibhM?mHCFKy!$SYIZm z^nK-FkL?aX;OGr2Wp9ue-w8B%(z3I#h8NK%2}LVUbQ`>v%!cP13$c{2IYR3efL0|< z(9Jf%XvSflBgv*ZbnN##5hO>Tn}O<~als+2ou98?C}@(n*r8{UpjdRe{-$36zSODsq2?xk-qlpxp=DKR3-;)ex{Z6Gy?`X z*xYD@)&Vk0Pqp=rSs&1enVdVA`~?RlR2w%nc>yi!b;>K<*hhNtZJ?GbNslOaG&?~Q z9)hHEkdFmpHT^ss=(ZVYl5PaEYFw_x49K%;;VnOHd=+ma_fD<2be;J`eh*!yU-k`P z{|;ckQi`tZh^w}F6wjEk)aPB*qUuJ4M7uUeXMF1WxHXH@_R=*s$Z)Kc&o9k+iPb#W zcbBNql`v>vTfYl*h$-KjHp3fZ6K){FCZJXh0+kt$zikG_SY;W7s(9vrfDbk5N%ec!^cMBk|8#-cFM% z(xBha`9P(5=Ti#0(mO3I1}cr+?gc2L8RYgZBX+v{Kh>Wt!BNDMZ7_hDZ6{u_gZ0lK znM3%>U{5j%1clwkyz7vwd^o?TQ?9ovEe6BM*#l=ADrrb$U3Mo;iz~3e=`Cau>iMw? zoA;+!%HO3aR3)O^^iAn5e8#cklr;C0W-#Q)K_pcCCmT8)9TL$LoZFy!VoN2vp~s}D z0aWNq(JI3zH&;lWHFF`<>%?ff#G8ycr9Z(aZ@cO6eF;SEOt72Z35Mj#ZT>S{ ztj&N8BHBkwH-j))=-A5Ft*1o}Ar>{pY;bd~##3Kjxk2nbdDh>a!8Y&?^XnZu+KCO} z(S)%bZtr?GbRK+l&HaV)WusIR$(*Z_oLZF$-^q^hM?eZ1dXF05VvUvdh;uR`Dh3-M>qNXKEQ(9(AYutWQ!=ez-m`z zg7l0oPxP@|ar)g#mVNg66FoPu{?8-CJxz0WKg5r6;@^>o!PM#i7 z?pbO`_J)GkkFWecw~v0F+ASYQ%&6LPXLB}E&Q!v*s?IAWJ#qTHJtp+PhMK2VY)aN0 zg#7{=*#TYo{A&!)s<^2lXn4}{CCRI}^|0+frCViG(9M%%CE(+(hXU->fm&oz3O4B} zx-D7`KgAlxdD4KzV8@QS_GC8XKmek)zD=xVY>ot2==Wt0gweg|wU;+Lb*}inwk{;6 zpwj@RsiE8b{{5AHeFq+sSI(%uC+K!^@-=z zgX-KjK-cDcd%NE77`)b7^3>+&A;I)ID*%9~LqCh=Z5lv&0=m*2A_`|A!mq;LCS;>Q zZMqW3EMsQ9G-exH7z~u!_g3sGx>z>-@3X-|YF;t4VuLGtz5%Qsr~~Ugvln)(uaFNQ zy=@TsNN!jbdhrBkN>!fGuY#VN6i_Z@7}70tueo@(%l7zf`@t*mE3O@dcMzKapJFVF zeul`1zJ?O3FRZ}2cAlix7T_$kpkRK&zBa^Y_?6)smQ1UAg-_hd?`!l8^tn;^SnN6& z-5eR@W8q3*YbV6`0O@W-g)R`iT9hXnp2|fY18$--mN2;_P<|qhWl#=p_dq#;CzToqn`lS zI~&jl1<;BUu!bkl)$S=a$dfc`i{^&@6HUGIF%w(y!jtUR`;PX%w;n{XPT^B%S{McI zOI6uU=zU6%YXGy{wOOHEXwF)&>^Pu;rE1&#G)xL+VlFCBq_Eufr0;m~SzS3R3Q>pk za0pMdhokiE;M)nvS7yqHH>(JnBzV-e6HMpN1#JmJ`>_qrGB6X-6E)^t%jLi9@Xm`w z?D^gKNm$zk6u?(G5j*jP-hN}zLY`<4(b~wj=k*&q%P%^?vtI`_uXmhM-~C1*>8vgT zJA_v=Pn|-MXZO7d9sBd`SEn5k>j+$u(OtiAwbe2k4o4c%!F#LUZE4g_1_SS}-gZ+~ zImLdL<@C$C1F4kAeUFMF_Khu%P&=x&g1rBL*MaTJgx){ZmQ$NBubw_U$~^O>x#gaL z!l-I+i=$)Z+J>joh{mvNzlw9EIjoUW92LFc;Rq!Fg`HRG(fIMnpb^k!^(~Vq3@%7 zgPuQmGPwt;7`Km_uhbGvEzCE2UniJL7B!0nm^P{~SX|FmhY$|r;B07?+6*#~#*ZqD zCwD#Ad2MC_;N_m#K}a+eZL(bAblbh_oIISyHZMi`O3X8Th!l zCUfxdqvNBpbBPSnfo5v_B;>=l&oGmY*r#71(OAj%X>!O`O|P|sc&;A?WyhR_XLZ~T zxfirLCmi^GEm6#NX_ zU%l1ROmD08-iyYK7ci`${I^%K@X-*ZT{RR`_ybR5|CIm z>moQ3LHpmaqA`ZDTTg&=anQlNLDd+@Z@JNf|d}sX+$PB3NGtI#>zi?MI2&-DGr< zITZ&Uw>D6IKJ5h}6s;6gfWfuiBtl_sN)p2$9ET1m*S+q28a;^lnLRaio+`d-N@?;O{eD;X z5gkife&~sW+6!DLvk1Luf#=$yo_iUkLtbpuUSv0UWDG`UgAU#(HKgHU9Y29c2^ zPgH56Kha2ORm%@>{aRn!Sof!KfJWbcKw=j`Fxw>IC=XgMUXkk1&(%+a^G<}vzCZBr zA{DfDJ51#|_+5NGrfgSp(eOnD$i1@X*@&x#v@1ZJa3) zVb93h2yd1Ag?m2}@$A3rK|0U@U6!!@jr?18)gN-7D%PuXempn;%ytNUOm`JlUVV^x znbrth#u$n?cONQR5>Mo07INe@*s`^&ves_Q&f<<=A`o<(tx&6*5u{0b|(8-dJ;E}wKqb?q#oDZ7JaVNK+(D@ULnOl ztaFVPketHGgaLc3;liN@Ia@9i>1_n_ySJvm$FFzI+gRL@s`%#?9?B*q6^7p0{xisD zZGkzwGS}^e78Ui;I^Siykri?DT~)?&c#|Hi@x)4rG-9 zrA=aj;DN3KO@LN5STHAB$2Z0#5g9sj!2Wm6pYu{SBqWN#q1c6E919EiqJDf>7*Qq? zpKI8#Q*;E+Eou0qhGR;9{cT!IKLJpiPwFd3nbPq4@>pR(t&IRGrS)7WY(E@BL$j~y zMeA=FiKrWzN`qSVKi$D(fk`%=^BKBe=1tNXc`RCRRgqksVqV~}oBCBTxiRvI!zCxM zUNj{ouGfJy#z+CadC|=*TfO2mc8%LXR7kfhHO7%^HqDE^KpbcwJl{XvMlzv8l98Lt<*z{SqTh`98!XwTZs=iN^xN(eS7^%! ze$(~ImWB*5Pa($H(4(QiKnE0221OMAp-7erBAL_kyD<|ASJP4Y_+NqD<)wA>h$X;5!E30{>?Z6` zIp{Sap2pmgm+aFTIPWlEp7Q0aX=5I65rKALa<5`0{1x*&*l_`I>)_cgku|RDcG^`u zufULb^Af4cJimrGBWz^kC4 z3kiu~VyNu?vKLUBe4O_nWVzW1ov!W#WxvZb|9x3t*mlG8ATH#s37Z}G2hcbI&!!IG z( zcQcUdeC;o2lkxrvK%%+}GGloVDHFH*xDRMvb(5d4*tH{e*UA8keab&7W*1&ApIXnw z_W+#@DK9X7kXElW|(rSZ$A^U87~ z1`)^|JcDh8kqXeN0W4JQ(q+&d5)J!wnaiWlw9t@;M(ZZv;Z4~9DfI8~@%(JtWq6%! z?*QrW2Fl-9PAcq;@_xWkljqy_^C$s_=1b$;T!PE|WM6)NR2H-lqFpRE3UA{gtMi)y za0t2QNn20Oe}64T30W8T`y=9TAOyhA0c5{@}#L{*xzJB#c!hNQnnT|hcw=9bkkK4 zN4`ux6GzxR5DJM|N!xe<4D0DlxlgA3c}+hJBV}pAkIiTNd98svkiSfc8qLDpN!n$j z-{4W|O8e7?RtD^PuFoZ}qWad2P_G3imsrcq3~=C{+`a!z1qiy`TFL?A*PgU}mfj)A z-~;`T?#D&#Wo9>1nQz4gNr&XEH1YvWMP?m7X9wp1`Uvh>fKz^&uEhkZAIUz$CApEn zLR?aH%G$>U4Hdw$0lI*I;@PQPu3@l(@b;WzT}Z4$59LAu5Bz0t#Q*Z1%K zX%?&T%ygWxWiIkDWCSYI2F7cJhnwEnm|^_gW+QKSN2C-#rIB~90Ti$ZYJv6BL!@?aG@uwqRmU`!!8zx#qW>n7oBACgv4h0eTjh6!{a_JF=2K~4w^+0^`2 zUvx;DVZZFO{(Cj1EUXvTd-+~U&h7^w{fQV$I2n!-V-;J}0s2}y9&f~dOcbF;wi+*YNsSq6q*!S`B(YvjYhMgbG#PD^FR&N0l^az3BfJIVK0}+6 zbecBQhF*+Gm;75?vzh8doGL@Rr0E&;iLNYs` zz5veb`ZZ;E0V;dDlKMX+}rUoC#T`4>9Q!&$sRy16unLwfs?tZc24jI z7d{-8QdaEV@@l%wI1Up1r2JF!Tn3uiH!*o~X~UlVVOm;gwLJDS{uf@4WjjY=Dw?yZ zx1pc>`mw~T+}u5p!^Mt6zrhb^>G_XGWuxOi<30aq_yX0;pEe7vS92cN1}N&(l<>dq zoEVr2q+D5cza_;0zqx9~&fE*Vsan5~)1zq~xoA(ZBB6&c@d~tG%-VfdIm*j0hIzcE ze-|hJm%K(B3-4NsPzp{*W}Ezgi>RVT!Hd^!g(^kf7FD}2`SmW(w&i4>t&Kyfz=t&oY2>ACBu?8?yF4e;`IDvY9J-ZgOnRbj7fQ_MU8U zLW_S?(z!h!r?Hjb=XBf-1GPUMU*eDVIlI!N$+pZw@dLIM2MC-jyK@oI*(SR$*!O&K z44R%DC=0FG-4mi=ZZiCmmzchjsVZF>RuVl3zcDub+2<_=%i6mT|Jaci}ukLDIVNT9?`+j3n zdh&(7={!1%ONoDG9#r}*<%!0Pg%+g~erNSeUgDn#J-8?l9nlsxLnwFPhq@b&jTj;{xb5yur<*fCQ zcXL2mY%TO>mcA2J>v3cPHtE6+`Cs>QL;$(_ZrDEi)>|hK6&k(SY84%Ka2resLZlyT zihppFXxcxw)v`6}%o^ut{fZ$+_i1M(*H+D>gl_n+y*YRD_9w4sbIEID)|*g<9jgEF za4Ej?kl!(Xk=!%6mET}Ce#`5_zIf8tb3b=i&(kiNd<8}O^Cegpm@9=?Hh|mTECLe& z7(TR4z!|J`FuY$4RJhVa&hHzvp(S7=`*cHvCOYoBk*u#=!IJ|6uMatnj}JX9Z~B~D z993HSrrcQ8_BzW+$-s)Hsy7}9CDUtl9b#05roE%-&ZpGhUny4M$OD?Or_^0Ko5*i1 zx^V2fz@d_x9szf!zqoc^pPUJHsdd@ccvI=7eB}297VQj0C5c2JTUJh&Nw#vJ_aONBz&x2B&9K0DBle4P4zwJxz0yEB}c9i@?@}wI07?D0K%iNH+MFI)5w7Hqf zcy#yJp5GpQ{#_^Kqk%}7)=eQY)zXM2NlwbkhPH3BrKMG@%pw4oxX>n0G9SA zk22p?muBEEc0(10;Pl_?BS!c?w{H}>Vg3M5#6R15{mI)(oHV>rm;PiYOo#VENXjIL z=V-d(?rV8z>Nk-|IU;CpqJmdN)FY(J3M0|I@WaOP`^zpXnn<~ym?-ipm?qjCTULr+ z-(9#qkFOQ9x{D8;cf5BIaVk%&*do#l+m-+1TgsD@Jn1aXiM=!=6)OICT?FYk7#0|Kt!o^r*r4r9WK~zMt9#c2Tu21&@1i?X zr~AjuAClC1X8c}Uns{)PZX(Gj+u{A`8TxZKopHAz?!FyuEtz4@-c=hGc;m-#{U=h0 z2{P8-)BMVQCv3)hYTV$;$G0LzqC)%foLhhxA3!e3&7PzIkcz!1s|e0lyo~O^de_(= zJ~#zMqrW>k;*m>1y#vQmKH5Ziw7<@dlxF$APbDh9rb>^d!r_taPlFS7QnLK-$ckWY zrUbqJ@@r+5LdaEJv7frX{{eX0f^Q5{9^47gUhM+~mo8sEYe2P{0@!=h_OP^x%u_%i zL4UepJiTl^X1{scVQ@FMEZMmH&If!D+|zedhmW_Bd!T~|Gn!`}PN~I|5mdoH5DZT9 z1pxYE63YlvfUof8-n>7ZG5>Srw*4LWJzW-?A6*8yhnKHKPlRRRI7#H*_dSB~#y*YUB0`f^PUdCw3BQe+qQ~N9hMsV7j?b&VgiBw%u_#eo)lYW{9weUog zZ3OJ+$Jt=r_+Cn%PkP#_%&b^ZY$IqrTJje`ltp9hpU5s2lG!BOgD+0Zo$-NP!BIuT3!zp_Hz+6aXrs6Ao+P}h zDr53~1QJnAX79ZaO1z{@bbKX7`T8< zWvc|!zJBjRS!AU%CUSi;Q1l)kvcTxwy?8fL_VFs97aFMgd;4BVHlCT`$DYo$BQPBQI_`b+lQ z>UZwYKdffQzeLvS|8`6?+kDp%yMwqDr!P00@r=#ydnS2dZD2V-NI3Q8>YbLly6TGs z*42M3`^zzAMq`ZU&C`*Zbbmc|eK?ilU8HTPw)RXA#_e<0s2^_OOgH5(Z+6K`4>sB% z4)^hBlOD76tSGpL2@Ly5SYre))j@|Eq<0htNBsw#L4bU*87z1S$JAxa!TP>s0ISBI zVXH*((N?}-Wyjvz10|;+UpSB>E)s=8{p#@uAeo*eOTgJ2!33H|A@orCkT+>gEK;pn zlEuM~saH!*03=@=MPYuvw(9$7zi+3-&F&!iBJSItayc4LI;Y+TsFix%%mo_I}-p7oe%|{ z0@{dUwG@!? z0e>hrz#^H=3=m9mwrd*w;LNd^nPa#7@1SosXUiwh^kdMY!6%aTWHW4AxuW%cxuz{B z7mIBSy}pwq9HG+XXc|+P`iP#Yjo+Q+rSi1w_$!tDj{atO3N7xW!|9YB2t%!6pc%%E** zK)Vytc=n6u_L9~|h-X&)(^XCUM^k%lwQ3fafxcTx8Y-?QKD_m^xv+3^iT`NsPdUZP^ z@P6#Gq8-PVe|Nzp;DYNQcLW+(!G)-rCS`mR5?bD@OGjKuWxz&U>JxPn#kKIP2&^50 zFTj%W|m+UYLXW@crKLeMygp(rv3)7D>vX`yC5H*-`$^h5S({^l%a^PYB6;P7v74? z@z+?#7yo%gG6(XL0E9avkCXRg`tVE?%iS2>>W`&d zpW+0t(U^m6OTCIQq&GOr^H>E6dHrteD_s7dqf~W(#z5C)Ds%CS`@ddS8HJplfS7Nw zDM*_%gHNB2lnpC0Mm4~NO5E7B{c-cPzku{%TMWy|!3I6AeU*Bl$WVmecs0H5MXrU_ z&$?odsq$3sbAQdz3y8@Ii9UnKDWVe;j27?4j?#F?@e`pl7>qWD!CS7`kw`3?UiA>k zX;FTl71#gy>}p~(oi1L@g8up*8kgWW*21AEpzmp3yym4B5o9d`XarD0VSL7XGZH0HQBhXz!@-d?SdgyPkJ}!j4i{zP zO6q!t_%}CELn6g6G-9!=~To7 z!@A~@je0j#MOQhdRE079C#(Ck{Y`n5bf6&cXMOI2V}=1jF#FG8J@-(7!!-i8UsKoz zsN4i#6bt%hw!YB!Avmk|yQgync^ew5E7DoX7~qeY3nX1#G8Hllye75 z?yn`|KZ24Tetj{iIXTn!iTGVZs5PSO9i>R%pX_&glm{!B;eVlC?TVJNc6@^yK~GEy z;Hu>;sN!+mfdOywF4)mLFlbPbc~kUXyd@MCp==z|``!8EL-Br@&>O(*4~xpS#r_w6 z=h+v4M8rW$t@9eB!N}^??>8pQr`4dBrK|$`6G-`VmG9x>daf83EjB7IF;|9 zOadq@of05xMPA;+Yya1K(o%3}AK-R$(ckhY3n&sxAVo_sJ8IPE=)BUc!Ha^RdHg`i zaIOL{Jk5HE>gBJcF$4(x-(jVs!XpsIz1@~sS6gtfZ>6mnwPdNgiLx)yy=72omC1iTp# zIlH*HsBmWI^w$wxnRN5X2OZGe-+2wnL+09^W+qF1!23b}6*fRxV|`_~EDBSD+KVam zb$?@Xfj(R)m+^nyts(B7gDEKp!KJ7ELcl0Lg=2cMfpo2q|7$jNW0xnNtx6&Ymv=&k zkMStBUPFzKSv{qTHufFoMF0*)GJXzJR^G%5K05Nd98ZOJ?!lth{xn;qP;L!?Vortr zO4efmhQTolrl0iE_%*PXCr?$Ax5W*DNe##@}#W7NpfBaY>C1 z%o3b?l3;%Wyz|lfA!zOQ!i`0T>t_Mnv(0Utv(eS`>^Im&kiQMy*eH0MP#3Q zxP(9^cx*uTPmoZ%lJhTcTIy#!MtN6xDO#{UwrH>zuw`A$!D)}gplMP?f5p91Hi7Iot?EkyZS6Q zaMKm#*)jXoooAL^B_Tn_ z<)8l*Xr5YdKjc(CQXNrrN3@`WdFsl>nWj(1P04Z??(yTVf~_{}I#m|@bZ_{viPKk% z*T(O>xBBAM9evD0lM+gt?q}LMahr9Slj_;pZ4w?;VK%su{s&csGpaSq7wLC(Y}z3m zOb}Y5d~i%Iu4cYuHr%PtB&8B~ZHXB|o0L2;zHlCf(mbo?r_X&Y?ZK2Vcja?McnNUZ z=rI0u?Nrz8kpJK>3P`h|?eDGgJMm1z+sLjPBzwofKgK`UTD2eb=6$d=3!OGVshHoO zY|2ydSVOsn*Wp5mWKHnmwKNHtaDIX71V6Qr!`5`0s-(>8c^$8@Mq6FK6;K!Wf_2Uz zDz2Co^#58NcSVZP&L8CwLlV&LpIVSB0?H`L`zI^F)jk_2P{u{JqMF%!a$##X@AWjb zBuuoBvIJW#7!oDY76!vU;TZ~W25Bo8vX2~={O03T={ZRL0D9XfZ8<{&&v@m{*NQ>w zr;Qx$YqJR@>NJTfWZ|6+)tkgMOU4ELbnEzJGU@rqsojeso+F2?foG)_n4_D4*$fIP zng1p79)_YGT^&1rj+^Ih6`2Dhs(Qd~)- zN8**!whHes6EbDBXoc1e=KB*FZ2#HHec-5@$484SpC+}-d?CewH1n8IVbX16^^({G zRO@P&!01?ee}Y8*oyY1GsV**ZT`XwmO@I;MV7U{TZvdUynp{b zO!@W4spS)QD}9vwnp-q^nZ+;4#EBJXL*!zG8QgHZ12R7V_uNQN&M-mc|KOM0^`|9t zyQgRBmTpl6UitdhPEEqq^!~TJVX18OfQvOsxKN96+>fKQM)l`9(B30>RE@r-r`c}a zrjV2DKQ5ifUE(YgC@8|_I^IMEMoWN#EG%XEul1mBoiZkgY!cA?M|!0j?}+|zZDQGO zJh;?BB%sG;i96`KJvVGHN?Qwiw1W=UE>0oiO6+%mtRC%jw81zAiSQJK6VuRRHO2_k z-k$XjpzQB-7g<|jd>c`p`^pzKNgZ%wuSwIGn43Cp@uY#;BJty_V~yx4PX4WwRD;_{ z*DFM91ah((95t05XSa9h%UbsCDVYFIhQC@$E{gaV0Tl@>S{jo%p{zNrqO(QSs^53VM@xb)OA2$}P1Tn1we2VSfP-3WbuuLONf;wC~vJ=t1` z{{F0UM4d##oWGEYA=YchF6bhHAQw5sAM!^;t&P+8io>m~6XcAjbV0Ml5Y$>sp=D-y z(83#1c!f$zRJXc{ie3N*8{;eAh{1V7vO;uy3;lu7W}~#JXX?X!4l+G>nP@oeg$~a4 z1Jt<>Hj6Hf8jmYr@b8w1rrZ13O95<;|1=e$Ugb*K1PTRMhmtWEmi}*=PbR8jo+#^h zC_l&Mu18x&5>e-UbB@3~r^e_jY7Y+0PB}L_kc$4QDC-4cR~dIeNo}DvSF#7ht&?yZ zGA-1HmZ0KAN*+!5;@(qV50{evG7>Ggh-!x~PH5ZRANqqu40-E;$f1#qs2mZ1k`=}||IGEb{9 zzpi>oGTFY}Xn*+R$pumYL6hu)BwfJDk+^wRTK72MTz2{b0KY;U-DqN&X!8KdC_OoP zj)hzgMPKTRj|Q_4P`S70LZ%*g@kLlsQ@S)wI-lbeXSmMdg0TPwr?pH|R zwhs@($+WLLU}YTgj0@fTrBgtfm?8C(Ps8o;uods7fOLbF-f+|O=I4O)!CrupzF!81;w*h{GjheC z9&rVW#OOtE-~r z)((p&U7euPS4^zg+^iw@H(-g&#i_C`mLp2zp%+WI`f)3UI}0+W%g*{@WYCE6%_G2t z8_Xcc!I=hlM!~vXsV6g@QZCzv)v~;aF^5C1!A`nFofkWmk2)HymN5@?82c2wD>QK| z;w}o* zZR&1dS$5#LezU5_Y}0_{UYl*9+j1qzFtr^oE~7lh_YdO!As4>Qve)R?`lPqLX$;2P z*imy~17cx&iwjQGYrDLzxo7@e3yC~&h4ggy$4X}Iv`@-nfB%OjU|~0-u+J;v#JcTtqIyv?@4mWMc7sE%7<1v zy~-xvyLZ~_ZOGvZcMc8DTz|@q(;Kik1sl83cyos(ey!eTmHMpeG|G0r=}Mb!Wse4B z+Uj61PNh|=25p8yiwglbuwSqbB?c@hQM6D~wVnx_UKoae?t{ z6T+PFa-l@mFjLaZNYE@WYL&P_7(lrtWA|4DonTweoY*BDqSL4B{Do^PQCgjqK5?5# zoa$@Q?domO>>Qrx%ec+|x=I%#6hrysJvVcieTk0U_M3__=nI@~vOHA6n5?kps(G)&FuWmR{N^qQ4d{$$WJF%=4t` zEt&*jFoaDVRj|Z~#Ey(U^+vDbi{~}^9$DiN3Xs`9vUL| za8iGSj*e>d+tcDSe+@D*jm(p5T;5W?HBREu-Q8xP4mU6okG}_7jON1A!W}*YJ{4GA zi#oIV(-~>UnaVeBj!hVTdhE&ebfrBiTd9Wb`G5OuTeB*!RAl=0msv|w53Mr@%GY#B z_>6VNr<`kS%?sWUPAx}yo0DH{?FMnCk@=F%Ysqgx^vi3>{o#HW-ha8f1~s6iYcDuU z$SYqGeBQ0P179aIgeQbLj6!2|f07#KYuaWDa{TtWVpfTq4m%rtyknj5!;xdAukOh5 zHk9}ERIO(YzPY^i+VMf7Jw^}T)RFgn+3FZ|eCG*Z=d)+9-u$n*kDg<$j$S&$n+vX| zrppo)%d+F7=FWK+J^f_x^o8VUw2E~-u6m0Yg^hGwBPH#|P3(&;)7BMfAMU=c8cG}h z!oo(5^2$OfCp2W$sgt6X5LHG!Bng1WfsKkx^?#9}1zB;@J#Tirh5{z(urXZv5lX=2 z61Qe`dN=gn5u=P14ro}~vupj><|jj={fRUe^b_>g*Y8ZTA@n1CQu-R>5WXgqIB3k~ zlwp;)3Y&k(xU=Cjd`d7f=FLD1q`Jl@-mIkSjab_ccpR7>p7S3v*+dOV0Zve5ioM0d zkiZ(WWF1M@o4$V%3B-x^Yzs>GJ^D1_JSR4t2i&}F^DTk6Smh~r4A1y%v`bGpF*`!i(E21rSUYrquGmV0v@kQJ30k_MpM-WiI#&(Of=rvS-JZ+2Gn zgUahUTZ|Em;g1lilni)raN#IQ&vgw`7_Ccu5~JX$A*x{XlYGN-htUJ{D60iptuthY zqzVSsAca-~5_PU5C2EKoC|-qFqGiKGe2P8pKR}r%0x=IYI=%5{!hbSM zSNmHQU=bysqn>_FkRTOL@L<0?`NW$v1_)-Pj>0$(=JP~4S7_!Z{I z;v)YIgo~54b&*tp(rZL;{4+7AkO=`AdLVMkBmBco6o1jK5|i= ztnK{skCW=kaksTXeXzAaW+hYM}Nu+-9?+(677x2<)Vj}AmO(e#JR zdOz=*Gj8bbFDmK2jyCAT7_^>2;UMc%YA${qJoYdvrKmn-4KpS7CQ`iqrgYZr;~5)| z@19mp+dv+@HuHC50F_VpQEbr*rt;dO< z#q*4VHBo3@#+aKJ7_EIIvM>@QG3>sB6gwOhBZhB~ZuMpxypS84uxmJUky)w4*miuh z;v7e<_(y2j$P(nTAcZTQ>%l%5JQofkbCEX?|CaObfW!v~w1o;5j5zP!0dH-8)&W@v zh1Gm10YvgGD$_PZti9dUx?xJ!#VPPJUOw(t`|X$Qv-y}3zaMXfvntPeyP!a%9_c|s z*(~Ewj+pQ|fV3>M!2kXo#5}PJlCO7VhlcJ^Cb$oixBG#nPU*VmQ*#YP|gLDn|6ju}&S!JB5Nu z%XyI$xgn#oj%c0i^z=(<(9MXy1tfZA0MjQyUsVl_c`vD3HuJrK?}<-+UN;wfl9bvi z^R#LD`K9$&ehiH?R}xN@QEwO%@S8>eUn(F6ow+dG1P(m_r{U&{jMeTUnI?&YiAj=| z!q`!+yi7W#g3oM0p-Is@TSy!)Cbp%xP(~NTLjN6fo&Wu1n4xP`PRsCK%)yEq_2yTPb06Dxl%ZTnCR$&*G1b(!UwaP zOpFS`>C}={*|FOj#h&&y{m<0}`r^E_cP8)<3tAYS5fJ`%#^CXeLZdZ&n%_1##ewW| z4%di|-%{P*%IIMpY%hR@k`c3wT2p;IL7CKBt}?k8mLHkKiR;2R@?+*;~hM34yb7a4pvY?t1=79<;4V|M{2)cl= z)cF&yjF=Nioh7Z4m*RdX6D_J0CD>@N!x$PZ`JZ3>w-ruMBJ0Epik-^z{0d3Je{wN!L}C?J(}MWu)Oiks0l$^2WjMU}jr%x2i4 ziS5G$#`@n4cY!EXV0?|hZn9BB7COeFw+V{)=qrKl1Q+`@XVj;41dRrQNr;Pp;@Q#q zB8y-6=2J`kB3IFx6Kak&|8k39B=tJk9q1x?5)hkF4*dGt`LC!q}q4F;!5O z5;R;a6}kkHL*KqC5Dkrv`OgFdse81TV~o}l;G#0LjQM}u5n6Gwg$X~BgrfoxTuD$I zUwG%gQlMSMPUHzpQtgK;2C#nxwS4|R^2_@FX~fG_;C2E5qgw`n{LpG4 z`f4E<{EsM5uR__p7pi&6ZCt#7?DywyIiuv`f`8w%`>k6+pbG)%KsNfFZ|^OL_N>6X z1n=oMW#s9nHJDBWrL$8mdCE<^9Uftx_pq@YDVL#2hdX_9=>I662)d!Vnr6phDfAsv z`V#B=>7$5+{Akwj+40!eb>@%LDgMp>L&nS%)QUJS2khKP{W_}~VrEZ^_L$rhEf{Zr z-cgIwPZ$-DDFFv>6-0>`{0|p2>M0P$6_qp^=`As=wO4F%rmO4GC37nM;H^K_D@1;+ z&BfTaP8`jRSi@#XevJM2zsho6M_^W`;GGAZ4g88*CKJ3frf1$+)ZE@+FEr~CDa^4A z-N3lzI{ig`sxkAaxr`&f*njhr(f`-pm%u~4y$|blOQmSJCbfO*{rgv&Axf)F{6Bl(#t%a z$Y=JgRUv^$0Pja}%Lc?uch)l31 z{q4HI8YKRNh&p_wL?t0cg=%Xu1*KO7GT#P=A7wK36=0nw7g5?xo*&>$-oY{-doArc zw2TH%yGGv4<(b{1lZeSR|AM7U(A;J~Rqiewt_ zC;6tQS(R%w*iDR}t)nXiwk6~lsyP~owKAx!S5CS~EqIF!UclV!fOw>c??DovOL}=~ zG)%HrbY=r)dz77v)w`PEIM%0{{)QoNo#}l0kh7~-AmGl(mP5zZ9k6DbvN=p5_61;`DavLN|#5$z+idB>sl2hN87*!hcS}9wg z$%rdw&DAFzM;=l<^{Bv2pf;WBiy+&_Drz^hQH)HrSab<|xiN$cAs1mJrwwfw4|glp zgX1~3BWD!iPo=H$(d^F18Sf=tGC8$yrVe`&G`wtF2T~QhaJeTW&B5XyX&v>8wd7`Q z@6_yj*gYH759;e^-t_Oktt22*G;nyst)GjV0Rf!7GWUBw&^Wj5Sf6Ql9i`kP-t+k@ zOoSc*x-Vzz4LMCNId=n^WZD5-dHBzk#WnmY=Q@QR@p=BOM|`mWcO{zW<5(R24(l%^*3AFO4!IdL5B1xBMLLX*g3BSL^0HSgO$c z*}Dk2kf8yZBy~KfP?Ysv4_-(+y&;5OUO+rjyZrRwnTKz&;X7U&M!i04<^zqJiX`;j z!Kb}Tb``J7c$+-ls%35t>PEkLY0CQ&Q}z=z%Kg#(3)i7a##9MW&s8^hW#GE#j9tpC z6JYNlUMOL0@Qo{)4lOwgCqudAcz{AplT58(&zo(bN2V_HpEhB3ZEi#g~ zMIbfg<-0=;$|q!Wo{pin=NNdcpY%T)kCv$-#wSe*KSF!*02(KMX)<~rYxI82n^lJo zw$rPzPfvO7>J^jTvgEh4(yW2F9WNLi`_@rc>F|$~0f}npqTr;8F?+LhiG^mGW>Zxq zACXecgvaiZW@&GUk{KtJKqG8d2J#>)50I^1fXDTyBEKpzFv0|Xs&2}RsE3?f>ldEe z)K4h5ayCoC{<+a>DDADaJq(Q8xy3|5N<;zpv>QW!b~r{}$TuEtEm*4WX&FzflxlFq`+>u>;=s+tZoH+=K8r(t zVoI?|mAVTBT&xrgy z1Fm~A`YuV3`oKH4YGRzsmr4?>Ua zP1jME=w3O!3LorCy>Q{e={aPy^U@w;j@jlZs3I$`=2!)nY_Qb_ReLpu^9N{dIgSsU zc)MQW(iM05$(jRl%hQ{*`W3vaf}p{G(TJVh7?+EyW>>^#eRMEemtd;mxMWBd#onN1 z+I*BFS59gPy}HQK7l6?UI%z0!9=n<4n0$K4F4RnS;Q>h@o~{f%sytGrJ}e_T<|#g{ z60=l=WC($(tqB2gJ(vn1%Xd(?ytb1tQZ5Cv_JXMM;G=HBwh7%pQm&cf6ro8_D=gqa zQ)S!dvQ>LOVlHvG3@{se)tCf!58Mj$`LNe`rmRQZ3*64&^ZYdI6bhmoCs@OLR<&3ul%l;+c!Vo3r3W`cbnclJ(<# zb`$*rnat=7pD5*N6`9QNPn4+&1E%=}?xo5s8*<*OvRl-?<75*BuZvtA_`$Nvc?C4v zqIgX8gi5`*)hG&z1Z1=7B?yqupy{$2={tcdPm0tD;&W79<6a_5?a9sihr|Z(b$QaSmzSVK zNN&bK%xjoMuWjE~-noE2v61YEwZ3Crz=wCV4pQo&$G8{=xwS5Wej5dVN-7`6Jl6@6 zf6hAi2gg=jB_`fxyP$(ciPwQ6U2cv&$?3o78KGnnqlQ+Lo_~c29-L^0%`{w@!&^+x zDs_2`5gP+6`+wE`C-(lvcL{7hGKTb_DuNKv3i7c$=SDmg#Dh38drO2NdGK7S4? zTaeb*XS%G!i#8%JAlUJNSRfgZS?5!}>TP}2UA*Er+3F|)Lz z(ki3b+A?r!`#@1tRB-fhR>z?gkYX#h`XScGT!~;MHMKJ54WXHa$#$dZMDK!)nKGoT z#C5mmmvwR!Bcr43(Eb+7*JKqHMQ>q!+FA9MG|^kT7sHGg*=J z{)+1ts9Y=sj5Q{~)wtuvD+K)RXWbrpQdEJ+)}^j0GtGCEM%v?hDESz=WvIa>0e_qd z6lS1Px5|{E{LDDyV_%4N*u)2VyDG}WEbNvcWjX#9dPi-I-`FeSTE98>GCYvM`dJSt zvyPW9+}%_xT`i>%X}3wam3RmtI7kNv+^9G|8zLbXyC?3Txns=5SlaOI1`O-O^ZcEf zfx{zH%Vyau;SZ4r?%7`kBH#!60}OZ#fQwVl z;Q%~4ADkT&^BQw@!6)udUO`YQ7BS^{99+(<{qfjm$PX@Vu9QW0?C``RH7%ds`F1BZ z4)_$k*?R7_C%P;*2;xFjCg`EG!Ie!N$ZKmVF#3d(Wx}T8K|Q}iPNo-AU#|5)o~*Db z2WWJiCeC60B9VkA9+tPi3bsMrt?B;YO3Qls!ZTA&490dLSSRI7hmG#|PLab;wTY0` z220|*)+_>_?CU?k-QHRbeFS?HPbpYO?g)%cDaJ(cAyB+QP!PZiptty{y(3yuIBGC7 zOfj)X&Coh{zuFB-i*0_Po$^DNWKhmX`=$D;BwZ=9v6PJpdhoILReZ10lXCtLEaFb~@aj&PIWoggb$l~;-DNL{Fvc(3XUpeQF6F%ao^x?O8@n`C&wc5!o z`VXy}nv-+yLm#F_&syVbY;erNd|`W^6S>vySCxD!4DiBYUIH&)Iy}i;{gP4t$?n%U zrdrM72SFTm#YlXrZR3InszrGs&RdUar}%!lv|4uCyi~r%aA6S+NA-eHcEiacgOA>;Qax6`3=r3v zG=L^LTcmZFqP~lo4ZykFIUxYz+JXEKbSL9dv!|k%9}tM@LwV!Rw>mkxw08rrrF z#cI8c7&X_#`%93SW**_MF|88dUUBeEs|n$(3_$FQ9qC?cQ7nJ4U=&L%=9MFT;ME?l zTRKC%3AT>(;j8<`<-x1+UPn79#aHnY9eUuRps~ZsRFBZt81gm<#k%T@V%1&5=S088 zcm;M*`aLg|Vg@=!aGSC`Musl}mgtkAN|%6F0`fIFD1qy0CiAyaJvLNfPWuBSOhCGA z7#mLltlk#EN;B3iwZ~>zd>+3;7*D|JQA@lrPusu=3l%dN1;OGe#LKP#?ol3bwZtI{ z2IXKGrk@ZjH*m5C?S5tNb6d&GJ~X!A>DWj5@d;ZwIc}}3U-p!SAsg%@PjmN%x#NQ+ znhHj4dpq?x8JBxnuA9)pDTVM^uGNvlWlm*=h9T=%42ydc@s0MHs$S)v9-3I@TaB*e z&ZGNsD|-<;-msYh)?io7aKH+=y4@$lB0x%^YNbaM^v+tmBf(d$FHfpbtLs4iuKd%> zif4FxiaU^Je^$#J4_w9W?6XKwWtZIo6RyvyzC0{G7N72ZVT4h_s%jp1J{0n!Ucj7Y5Dl&r>#7@?8X2oY zKQgG--C+~`G|+MQ9AsbFx}i47x$H*geNp+F5dmNJJdwW^K`etsft~$@xJE*Zn#VY` zrZc8%qF>I-o@DT*tDMKpGKIzKR~$eu8(iH_2sbV7t9+d6+?_orkiSedTQ+pCbZxIVy@zok>iGH*0dC$ zsN%?5jZCBD`1FmOrgl&Y?m?$Ccdt`1SlhwD zIS3lB!uU7*N{D}wHxSQL^VH}Ub3w*}JgSapX+J9?gvu{jFy^%T`0tv)^ zyg!=zd6S2vUsB*fm{il$77=J$pwFW9PFWSd+(jGYAKdekf35AY)|XmumcQAKd|m6d z2>;>UW(VJ`rH_4VUQTyPTvG9juKZPZi>h);i72315JW1)=n_kIHD0)sr^d^nIEn=} zDBLI%k&PXtu6lIZ=W7d&faTSn`vWfI>MqL!CJzU}fJ%&a1qN;I5Wbj0O)Py3LFNe& zHYJ_75w*om4eP-X>YKOQPGKM=H_emEB= zA8dHc_CJhwFo<#R+=mAg`pPVDmTO9rl|~sqv9ZGRo%ni*2mj}JycCYO0;&&0&a8tlMA15s8A$$Fh^3BZ3ROOO* zVUvw(%GVF=kmB)Pb<~o?9}naA#t}V&_>A26Ku9p!Y-y9XDEF2#kf`a>rgxyE2iE1s z;hI<|8Q}x#bJci%&!?3m-GpuY*ITC;{`5qa2z7gOEkw9Hx(Qm5d8*?Yc=O6?*&`3t zRhhn5(PZ!v(u=sdBnGB>JX3*%^Fp6{wrKmCjPnm>`$M)rkonV#&$!`BIcVpJzcINQW}JKym-l5o#ZVW=$OrHJg#bB8ltS8*G=AZ)e??`(eV z6lu+Hwmya81rOPDQlM=4Dz0sBRxjrIT?YPS*ooxg;+kVOF0OfAgMYFa4Wy!Y*^D_0 z2KexsG;II|0NG$LAo$UNWV7om*dNkBt>BLh1_Od0FsuIoY(8yHEWSY!2*CG6u;pbA zi`g`aMw90jHgAK^8>v%~2OU`(VcrH&ES;}GApqE=Kqk4ku7OLiY9pqb$3J&>PL98w zY|?{841je|?#i>ekI#%;p6MR<7pm)J%woI`?5t6%!ssw{0$9VY6S{coIdnmS<>s$- zx)|urm4uQh6di5b;_EroT~l!*7Qu@}0EuJcbt_M39uH>)Zh4rZY+IAk6eC3i%J@ac^ z;XV3FqZqlnYSP6iBNWy=phy&ptUwjXo6?=RQf)L(5aA9=-4LQS%$ihxytAA3uXz8>i`92a8iKJp;`1Uu1SdveCVUU#o0oe)=<_fC9Ubiu~ zp(^`L^G(?#YU)*-w`sn^MkB1yT7j@)0u^@bWE ztlLu7Ruqe>?B6<%98qOGd#sp6#o3LX=b_7h#}rt2OkerRemOZ`vMlKj`I=sS-1!QvO{ntvC=Ia1E)n!m>IpQ|jlfORl7Tl^RwP-f!1t3w+COdUGHa(5A#;o!E-InCE#DDU$-Br`;5LaJmadd5_$#s?Q;rZAbNd6z=z zkr_`QMf0I_W};aPn(94*MCS*<1`a?A$d;gD1VX{M;0TFOMQ~TP>!Re*{021Y%@`Ey zFyrKCIf8ttnWOMfl~>S}m??udPs(HKX$Qun zJu4W>wA(y8=v+fsD#~^pHGp|a`S5UhH=bq!a;1Ko z3*jsu)uE8L>a-TKxPaUuQWqF&H}HW*tf(a9>3aFQ?cL$*NUyb>A8e0P8Hl{xNCeP5YVW zXxkTbhKlz93I4O{L=IMoPMK3NbzkBon*P6#iZy_}e_aE)!r|hR9 z3P&&7_-?tfeQ!KZEBQrQ?@GPU$@_Arz?97v$Aqf zhB!vt4(Eo0xbjQ#Wh`p(G!~+Lvf5=&=9@6nFOr=%AYzoLB8c9VCF+(<`xDfDeT+WY z=tLU1*S*J3Ej!P3uaL>e-q?$iJ&rkKjdb#;p=ly#5JGztq&m6XJrtF2KE69? zt3@oE-n*IHvTokaqXb5Xl2NO1yH_{N3%qJAdGP&B8>e>Nc@toY8}e-5Iv4%ahLQ<^ zF8vOj(pbjU(mkCN^N-6k_q<)MIrqg1ShME0LbeLsnj7O1qaY)f*WiPJhvS@nON@Zp z&t^yl)DmtQtOZI5kS`nX+#VJD5wJzyZ#7%`-&bKULL%&N*u_dw~(vZkQK=l1AuzJLG_KLJoK{=3mwFeYPJ&?wf31Yx!^8 zCeVx@Avl|ooPNSl|8~;CXxtD{S`7=+>JIy;qlWHZYn$bU|JU8?pZ7P*#D9sv&Z>#; z)Xbk~lWzp}$L0LLq)k7nA-`#p66?Q87yi98VmJP42MV~cwbGvm%Q-6V&#*ZC{KZ(} zlzOTX**PucgbT9$quca@ z$bCbKW{fkM{ozj<`wfl$Bl>urUA}hU_e0$eBKJ);nh3d``1i`he_m0qP;%M`3)9Be zt%`S3$Nt)mn>W+GQ9|<;(Y*QhpGW-kXQjfzd#630!9NZPV{* z^zF2%^rAL z*T}^VFxB{;G=HSPHndgu)*vDZ3 zuGff1QhKQW{I2 zvdB0p;N9kLe_zye1Ot8picV1SnHh7)ZO@W!hfF179CitA+w`gF^M5dhYZt?E1 zkxA|`a(+&3D4HQG>EaDMjpEH$q^^x+UMr0dhWSqfq4vHW)Xs%E3JlVDaQuID~;XQjsz3BOOBJxDW%}tDTC0cx$rlb)CudA)#mTrW*Iey|w08fTZGl!J3xK6b56AG z9UYD6yIqWPQO@$ZYxW8BOiCF>=RHLu`c9kVYFSyLGf@5Ljdq@)xVcC4)Sc<6|w!$c}>ij!Yv;AcDHaW}sXJ=j& zHZjSSouKcWd5^n7lPzhx`DK0c$l~Vn_IfB@RW+(sr#g)?VuFat96Cu(+eWQu)ZJ_R z3ra>Tm`Cu&m(1PN8$NZiF}iup8!&Fpr|#zw-r)!~&ZZq1p7MLis;@DZX+Kko>BbMB zcg;*$a*D*^Z8j-NU2PdTc{YX~Nn2qV_>_dDms@3#^X_KNbm96U1lsy8x}ASMk!~xI zY`-%M7PG5*C{|%Ng&r}zQ`uiAwb9o#$M@V_sLWE2?5V0W@kJ7mGI7~!!mJt`e?hjN zqvdgp0xaavX}gM&qJymkA$uie8Q^Z0V5p>+Id)yXDYe$YRnH<<8+AzEgLGOwZNL*x zl(oq>PRMhc$~I6T2|nrZ++bNzdPP}Orvw_pl62TA1#B8?75GvU&pll&_TE_Tvr|ta za}#ySbLXkiy$z1i)WVb2)V?hg32XE+n}MsTQ_e;e4=ci-;39mVxq8>QNA|^)V$9Wq z`2&OY*2Y@d-_U*l-ONFe44>F#g+ZxS);FgRVe(3ZP_c@b#{o)Fi7_EsDQnnDQ<;bm zj8+nH-?N)6Q`FeLks4Biku4L^my#WEq=Q|5>I}-ZmntSusGBqq7X($dQ^;XZ=NBjr zhmYtIC!Oxfu=pTzm3EvO4|GdHwnrpX!q-J9HN{(7rlpQV?eJGWD{RSD=T(x_DFG+z ztA=8{0{;82@H<%?UD`d>PZ(Tr83u1Lq^l8z2eKuKddJuJy;GtWbOPH6t*DI1VoBP3ybFtq^SRx2jTMB6 zRYThhI`g{S&nv=O%rX=j9H3lu@DgcWS#%0>uE+M73MS7(D_H#r^wLt#{_)4r{R7%a z(cISjU0Q?j9|8C8rQR@a?u^0d4n4fQYdln);=YRP8EH>Hk+eimRCZP1jhp2W2>l%@ zbtpP9V;w827jBgW-7bt~Z`4mMd?tjhO;$RapzIMI(&}W22y}9~(WkGIHo_O<6v7t8 zr6|_FS(l5caZ{4ll_d-?Q^&NKX_ z*EgQqvN3!mLGaa;>+f~XS`vsS4p-3>o+@hYF6O2(#oZ9!5h z9VorR_7F#AlXy$TV84ANzPx2$osDR^|1gnQ^?)}mB^|OlXq9nrlM-Edvhk^BQ*SaR zz|-rLt=;RAKB3r?BU!;^uzk{Ni08pqhH9Ra&H1u9QIJ8c5q<*wb_wkPZE9V-MoTbk z{ZcIAeJQ4CeM&%ZNK9%4AplD*dMM;99Kzl1phAt3PbtVsHj8!}!wy|R|1KlrHC*mr zvDUZy7`~j^;&;?QIj-@ks=__1qC;6$I94;eP7}PpsfVy&EJo0~{pjd$?kz_?&uK^W z`wWQIP1!geq}DLrJvnH5_jB}0e;;Q>p5H=bxxDsJ18S+IehIpeh2#CsbynOpjNfXM z@8g#GCxyy5M`@Exor1bjkt)BIw3D=`H!jN-H10$@<@IRPX{g>FjnBro^rb0(P;o=I z$Zz*+jWe4PNSnk*ojf117?5ECXrwnI9ZjQ!U8DQS#=LK$a$S(WtK_L39aZ+ze%yX1 z80x)~IDT@pVqmneD6p{l?%+?(q0nBxA%(Q~WS7*z-IQK_yW~~RrKDrb@-}S<3^umE zS81;(emUb^g>UdshEh^Y=oH;T7t}Q(PqlsPF;GqtNRFvaJ}>%75K9kfUa1hJOxfEy zQgsjJym~OgOnQMmhh?TBqpJ7ePhf(8VpTe#W3$fP1s4KJH0(jGFV8?Q{buxcShdptbhX%78_S6TS2(qhyk1~Q!@Rnls3<><3 zO#@RC_G#sBz~H0>$?VeLbB^Eu@hrmd)d1`ou1UwYH&%jkOdy8hO_VrU=L8P*g2-#k zK9$orTT5V^%_b!zkouC?mNl3a$X75jL@MTvIPmTib=Dc5Gs92RwVgQIRJwBx%WLB{ zj$^TIh&dEqxYMU9O4x%5m`fz9knCfMLX8ow?DIpwu%FCq*`q$J#Co^WA%uPDD zMoYw802Y5e_v6rJo_@1L15IN$;$KbXIN)N literal 0 HcmV?d00001 diff --git a/x-pack/examples/lens_embeddable_inline_editing_example/public/index.ts b/x-pack/examples/lens_embeddable_inline_editing_example/public/index.ts new file mode 100644 index 0000000000000..4a3eb7100ffba --- /dev/null +++ b/x-pack/examples/lens_embeddable_inline_editing_example/public/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { LensInlineEditingPlugin } from './plugin'; + +export const plugin = () => new LensInlineEditingPlugin(); diff --git a/x-pack/examples/lens_embeddable_inline_editing_example/public/mount.tsx b/x-pack/examples/lens_embeddable_inline_editing_example/public/mount.tsx new file mode 100644 index 0000000000000..411538e2df2ca --- /dev/null +++ b/x-pack/examples/lens_embeddable_inline_editing_example/public/mount.tsx @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as React from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; +import { EuiCallOut } from '@elastic/eui'; + +import type { CoreSetup, AppMountParameters } from '@kbn/core/public'; +import type { StartDependencies } from './plugin'; + +export const mount = + (coreSetup: CoreSetup) => + async ({ element }: AppMountParameters) => { + const [core, plugins] = await coreSetup.getStartServices(); + const { App } = await import('./app'); + + const dataView = await plugins.dataViews.getDefaultDataView(); + const stateHelpers = await plugins.lens.stateHelperApi(); + + const i18nCore = core.i18n; + + const reactElement = ( + + {dataView ? ( + + ) : ( + +

    You need at least one dataview for this demo to work

    +
    + )} +
    + ); + + render(reactElement, element); + return () => unmountComponentAtNode(element); + }; diff --git a/x-pack/examples/lens_embeddable_inline_editing_example/public/plugin.ts b/x-pack/examples/lens_embeddable_inline_editing_example/public/plugin.ts new file mode 100644 index 0000000000000..5d970e2667ff7 --- /dev/null +++ b/x-pack/examples/lens_embeddable_inline_editing_example/public/plugin.ts @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Plugin, CoreSetup, AppNavLinkStatus } from '@kbn/core/public'; +import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; +import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import { LensPublicStart } from '@kbn/lens-plugin/public'; +import { DeveloperExamplesSetup } from '@kbn/developer-examples-plugin/public'; +import { mount } from './mount'; +import image from './image.png'; + +export interface SetupDependencies { + developerExamples: DeveloperExamplesSetup; +} + +export interface StartDependencies { + dataViews: DataViewsPublicPluginStart; + lens: LensPublicStart; + uiActions: UiActionsStart; +} + +export class LensInlineEditingPlugin + implements Plugin +{ + public setup(core: CoreSetup, { developerExamples }: SetupDependencies) { + core.application.register({ + id: 'lens_embeddable_inline_editing_example', + title: 'Lens inline editing embeddable', + navLinkStatus: AppNavLinkStatus.hidden, + mount: mount(core), + }); + + developerExamples.register({ + appId: 'lens_embeddable_inline_editing_example', + title: 'Lens inline editing embeddable', + description: 'Inline editing of a Lens embeddable examples', + links: [ + { + label: 'README', + href: 'https://github.com/elastic/kibana/tree/main/x-pack/examples/lens_embeddable_inline_editing_example', + iconType: 'logoGithub', + size: 's', + target: '_blank', + }, + ], + image, + }); + } + + public start() {} + + public stop() {} +} diff --git a/x-pack/examples/lens_embeddable_inline_editing_example/public/utils.ts b/x-pack/examples/lens_embeddable_inline_editing_example/public/utils.ts new file mode 100644 index 0000000000000..f0069a543d368 --- /dev/null +++ b/x-pack/examples/lens_embeddable_inline_editing_example/public/utils.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { DataView } from '@kbn/data-views-plugin/public'; +import type { + LensConfig, + LensConfigOptions, +} from '@kbn/lens-embeddable-utils/config_builder/types'; + +export const getConfigOptions = (dataView: DataView, isESQL?: boolean) => { + const index = dataView.getIndexPattern(); + const timeFieldName = dataView.getTimeField()?.name; + if (isESQL) { + return { + config: { + chartType: 'metric', + title: 'metric chart', + dataset: { + esql: `from ${index} | stats count=count()`, + }, + value: 'count', + } as LensConfig, + options: { + embeddable: true, + timeRange: { + from: 'now-30d', + to: 'now', + type: 'relative', + }, + query: { + esql: `from ${index} | stats count=count()`, + }, + } as unknown as LensConfigOptions, + }; + } else { + return { + config: { + chartType: 'heatmap', + title: 'heatmap chart', + dataset: { + index, + timeFieldName, + }, + xAxis: { + type: 'dateHistogram', + field: timeFieldName, + }, + value: 'count()', + } as LensConfig, + options: { + embeddable: true, + timeRange: { + from: 'now-30d', + to: 'now', + type: 'relative', + }, + } as LensConfigOptions, + }; + } +}; diff --git a/x-pack/examples/lens_embeddable_inline_editing_example/tsconfig.json b/x-pack/examples/lens_embeddable_inline_editing_example/tsconfig.json new file mode 100644 index 0000000000000..e4727650106bd --- /dev/null +++ b/x-pack/examples/lens_embeddable_inline_editing_example/tsconfig.json @@ -0,0 +1,26 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": [ + "index.ts", + "public/**/*.ts", + "public/**/*.tsx", + "server/**/*.ts", + "../../../typings/**/*" + ], + "exclude": [ + "target/**/*", + ], + "kbn_references": [ + "@kbn/core", + "@kbn/lens-plugin", + "@kbn/developer-examples-plugin", + "@kbn/data-views-plugin", + "@kbn/ui-actions-plugin", + "@kbn/kibana-react-plugin", + "@kbn/lens-embeddable-utils", + "@kbn/ui-theme", + ] +} diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts index bb36de888b407..75a5c42c76444 100644 --- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts +++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts @@ -118,7 +118,7 @@ describe('Lens Attribute', () => { ReportTypes.KPI ); - expect(lnsAttrKpi.getJSON().state.datasourceStates.formBased.layers.layer0.columns).toEqual({ + expect(lnsAttrKpi.getJSON().state.datasourceStates?.formBased?.layers.layer0.columns).toEqual({ 'x-axis-column-layer0': { dataType: 'date', isBucketed: true, diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration.tsx index acef8feb6da50..0944326cf43c2 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration.tsx +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration.tsx @@ -117,6 +117,8 @@ export async function getEditLensConfiguration( isNewPanel, deletePanel, hidesSuggestions, + onApplyCb, + onCancelCb, }: EditLensConfigurationProps) => { if (!lensServices || !datasourceMap || !visualizationMap) { return ; @@ -212,6 +214,8 @@ export async function getEditLensConfiguration( setCurrentAttributes, isNewPanel, deletePanel, + onApplyCb, + onCancelCb, }; return getWrapper( diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx index e3df96840c883..1aae97977d714 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx @@ -65,6 +65,8 @@ export function LensEditConfigurationFlyout({ isNewPanel, deletePanel, hidesSuggestions, + onApplyCb, + onCancelCb, }: EditConfigPanelProps) { const euiTheme = useEuiTheme(); const previousAttributes = useRef(attributes); @@ -173,6 +175,7 @@ export function LensEditConfigurationFlyout({ if (isNewPanel && deletePanel) { deletePanel(); } + onCancelCb?.(); closeFlyout?.(); }, [ attributesChanged, @@ -186,6 +189,7 @@ export function LensEditConfigurationFlyout({ updatePanelState, updateSuggestion, updateByRefInput, + onCancelCb, ]); const onApply = useCallback(() => { @@ -220,10 +224,12 @@ export function LensEditConfigurationFlyout({ saveByRef?.(attrs); updateByRefInput?.(savedObjectId); } + onApplyCb?.(); closeFlyout?.(); }, [ savedObjectId, closeFlyout, + onApplyCb, datasourceStates, visualization.state, activeVisualization, diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/types.ts b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/types.ts index 6b5a2bb501275..bb6b1157f43b9 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/types.ts +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/types.ts @@ -82,6 +82,10 @@ export interface EditConfigPanelProps { deletePanel?: () => void; /** If set to true the layout changes to accordion and the text based query (i.e. ES|QL) can be edited */ hidesSuggestions?: boolean; + /** Optional callback for apply flyout button */ + onApplyCb?: () => void; + /** Optional callback for cancel flyout button */ + onCancelCb?: () => void; } export interface LayerConfigurationProps { diff --git a/x-pack/plugins/lens/public/async_services.ts b/x-pack/plugins/lens/public/async_services.ts index 85724c871cda6..28becae5e6071 100644 --- a/x-pack/plugins/lens/public/async_services.ts +++ b/x-pack/plugins/lens/public/async_services.ts @@ -52,3 +52,4 @@ export * from './chart_info_api'; export * from './trigger_actions/open_in_discover_helpers'; export * from './trigger_actions/open_lens_config/edit_action_helpers'; export * from './trigger_actions/open_lens_config/create_action_helpers'; +export * from './trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action_helpers'; diff --git a/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx b/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx index 986f2f65c693e..bdbcfb49617bb 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx @@ -46,7 +46,7 @@ type LensAttributes = Omit< visualizationType: TVisType; state: Omit & { datasourceStates: { - formBased: FormBasedPersistedState; + formBased?: FormBasedPersistedState; textBased?: TextBasedPersistedState; }; visualization: TVisState; diff --git a/x-pack/plugins/lens/public/index.ts b/x-pack/plugins/lens/public/index.ts index c611952f44f0a..a9f8e0eba3dc4 100644 --- a/x-pack/plugins/lens/public/index.ts +++ b/x-pack/plugins/lens/public/index.ts @@ -106,6 +106,8 @@ export type { ReferenceLineLayerConfig, } from '@kbn/expression-xy-plugin/common'; +export type { InlineEditLensEmbeddableContext } from './trigger_actions/open_lens_config/in_app_embeddable_edit/types'; + export type { LensEmbeddableInput, LensSavedObjectAttributes, diff --git a/x-pack/plugins/lens/public/plugin.ts b/x-pack/plugins/lens/public/plugin.ts index 872e1a566ab20..61ffb1d0686d0 100644 --- a/x-pack/plugins/lens/public/plugin.ts +++ b/x-pack/plugins/lens/public/plugin.ts @@ -107,6 +107,11 @@ import { getLensAliasConfig } from './vis_type_alias'; import { createOpenInDiscoverAction } from './trigger_actions/open_in_discover_action'; import { ConfigureInLensPanelAction } from './trigger_actions/open_lens_config/edit_action'; import { CreateESQLPanelAction } from './trigger_actions/open_lens_config/create_action'; +import { + inAppEmbeddableEditTrigger, + IN_APP_EMBEDDABLE_EDIT_TRIGGER, +} from './trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_trigger'; +import { EditLensEmbeddableAction } from './trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action'; import { visualizeFieldAction } from './trigger_actions/visualize_field_actions'; import { visualizeTSVBAction } from './trigger_actions/visualize_tsvb_actions'; import { visualizeAggBasedVisAction } from './trigger_actions/visualize_agg_based_vis_actions'; @@ -575,6 +580,10 @@ export class LensPlugin { if (startDependencies.uiActions.hasAction(ACTION_VISUALIZE_FIELD)) { startDependencies.uiActions.unregisterAction(ACTION_VISUALIZE_FIELD); } + + // this trigger enables external consumers to use the inline editing flyout + startDependencies.uiActions.registerTrigger(inAppEmbeddableEditTrigger); + startDependencies.uiActions.addTriggerAction( VISUALIZE_FIELD_TRIGGER, visualizeFieldAction(core.application) @@ -600,8 +609,17 @@ export class LensPlugin { core.overlays, core.theme ); + // dashboard edit panel action startDependencies.uiActions.addTriggerAction('CONTEXT_MENU_TRIGGER', editInLensAction); + // Allows the Lens embeddable to easily open the inapp editing flyout + const editLensEmbeddableAction = new EditLensEmbeddableAction(startDependencies, core); + // embeddable edit panel action + startDependencies.uiActions.addTriggerAction( + IN_APP_EMBEDDABLE_EDIT_TRIGGER, + editLensEmbeddableAction + ); + // Displays the add ESQL panel in the dashboard add Panel menu const createESQLPanelAction = new CreateESQLPanelAction(startDependencies, core); startDependencies.uiActions.addTriggerAction('ADD_PANEL_TRIGGER', createESQLPanelAction); diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action.test.tsx b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action.test.tsx new file mode 100644 index 0000000000000..a6c7a8bcf6bc0 --- /dev/null +++ b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action.test.tsx @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { CoreStart } from '@kbn/core/public'; +import { coreMock } from '@kbn/core/public/mocks'; +import type { LensPluginStartDependencies } from '../../../plugin'; +import { createMockStartDependencies } from '../../../editor_frame_service/mocks'; +import type { TypedLensByValueInput } from '../../../embeddable/embeddable_component'; +import { EditLensEmbeddableAction } from './in_app_embeddable_edit_action'; + +describe('inapp editing of Lens embeddable', () => { + const core = coreMock.createStart(); + const mockStartDependencies = + createMockStartDependencies() as unknown as LensPluginStartDependencies; + describe('compatibility check', () => { + const attributes = { + title: 'An extremely cool default document!', + expression: 'definitely a valid expression', + visualizationType: 'testVis', + state: { + query: { esql: 'from test' }, + filters: [{ query: { match_phrase: { src: 'test' } }, meta: { index: 'index-pattern-0' } }], + datasourceStates: { + testDatasource: 'datasource', + }, + visualization: {}, + }, + references: [{ type: 'index-pattern', id: '1', name: 'index-pattern-0' }], + } as unknown as TypedLensByValueInput['attributes']; + it('is incompatible for ESQL charts and if ui setting for ES|QL is off', async () => { + const inAppEditAction = new EditLensEmbeddableAction(mockStartDependencies, core); + const context = { + attributes, + lensEvent: { + adapters: {}, + embeddableOutput$: undefined, + }, + onUpdate: jest.fn(), + }; + const isCompatible = await inAppEditAction.isCompatible(context); + + expect(isCompatible).toBeFalsy(); + }); + + it('is compatible for ESQL charts and if ui setting for ES|QL is on', async () => { + const updatedCore = { + ...core, + uiSettings: { + ...core.uiSettings, + get: (setting: string) => { + return setting === 'discover:enableESQL'; + }, + }, + } as CoreStart; + const inAppEditAction = new EditLensEmbeddableAction(mockStartDependencies, updatedCore); + const context = { + attributes, + lensEvent: { + adapters: {}, + embeddableOutput$: undefined, + }, + onUpdate: jest.fn(), + }; + const isCompatible = await inAppEditAction.isCompatible(context); + + expect(isCompatible).toBeTruthy(); + }); + + it('is compatible for dataview charts', async () => { + const inAppEditAction = new EditLensEmbeddableAction(mockStartDependencies, core); + const newAttributes = { + ...attributes, + state: { + ...attributes.state, + query: { + language: 'kuery', + query: '', + }, + }, + }; + const context = { + attributes: newAttributes, + lensEvent: { + adapters: {}, + embeddableOutput$: undefined, + }, + onUpdate: jest.fn(), + }; + const isCompatible = await inAppEditAction.isCompatible(context); + + expect(isCompatible).toBeTruthy(); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action.tsx b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action.tsx new file mode 100644 index 0000000000000..c132b5e88c6c4 --- /dev/null +++ b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action.tsx @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { i18n } from '@kbn/i18n'; +import type { CoreStart } from '@kbn/core/public'; +import { Action } from '@kbn/ui-actions-plugin/public'; +import type { LensPluginStartDependencies } from '../../../plugin'; +import type { InlineEditLensEmbeddableContext } from './types'; + +const ACTION_EDIT_LENS_EMBEDDABLE = 'ACTION_EDIT_LENS_EMBEDDABLE'; + +export const getAsyncHelpers = async () => await import('../../../async_services'); + +export class EditLensEmbeddableAction implements Action { + public type = ACTION_EDIT_LENS_EMBEDDABLE; + public id = ACTION_EDIT_LENS_EMBEDDABLE; + public order = 50; + + constructor( + protected readonly startDependencies: LensPluginStartDependencies, + protected readonly core: CoreStart + ) {} + + public getDisplayName(): string { + return i18n.translate('xpack.lens.app.editLensEmbeddableLabel', { + defaultMessage: 'Edit visualization', + }); + } + + public getIconType() { + return 'pencil'; + } + + public async isCompatible({ attributes }: InlineEditLensEmbeddableContext) { + const { isEmbeddableEditActionCompatible } = await getAsyncHelpers(); + return isEmbeddableEditActionCompatible(this.core, attributes); + } + + public async execute({ + attributes, + lensEvent, + container, + onUpdate, + onApply, + onCancel, + }: InlineEditLensEmbeddableContext) { + const { executeEditEmbeddableAction } = await getAsyncHelpers(); + if (attributes) { + executeEditEmbeddableAction({ + deps: this.startDependencies, + core: this.core, + attributes, + lensEvent, + container, + onUpdate, + onApply, + onCancel, + }); + } + } +} diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action_helpers.tsx b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action_helpers.tsx new file mode 100644 index 0000000000000..584aa7aaf132a --- /dev/null +++ b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action_helpers.tsx @@ -0,0 +1,154 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import ReactDOM from 'react-dom'; +import type { CoreStart } from '@kbn/core/public'; +import { isOfAggregateQueryType } from '@kbn/es-query'; +import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; +import type { LensPluginStartDependencies } from '../../../plugin'; +import type { TypedLensByValueInput } from '../../../embeddable/embeddable_component'; +import { extractReferencesFromState } from '../../../utils'; +import type { LensChartLoadEvent } from './types'; + +export function isEmbeddableEditActionCompatible( + core: CoreStart, + attributes: TypedLensByValueInput['attributes'] +) { + // for ES|QL is compatible only when advanced setting is enabled + const query = attributes.state.query; + return isOfAggregateQueryType(query) ? core.uiSettings.get('discover:enableESQL') : true; +} + +export async function executeEditEmbeddableAction({ + deps, + core, + attributes, + lensEvent, + container, + onUpdate, + onApply, + onCancel, +}: { + deps: LensPluginStartDependencies; + core: CoreStart; + attributes: TypedLensByValueInput['attributes']; + lensEvent: LensChartLoadEvent; + container?: HTMLElement | null; + onUpdate: (newAttributes: TypedLensByValueInput['attributes']) => void; + onApply?: () => void; + onCancel?: () => void; +}) { + const isCompatibleAction = isEmbeddableEditActionCompatible(core, attributes); + if (!isCompatibleAction) { + throw new IncompatibleActionError(); + } + + const { getEditLensConfiguration, getVisualizationMap, getDatasourceMap } = await import( + '../../../async_services' + ); + const visualizationMap = getVisualizationMap(); + const datasourceMap = getDatasourceMap(); + const query = attributes.state.query; + const activeDatasourceId = isOfAggregateQueryType(query) ? 'textBased' : 'formBased'; + + const onUpdatePanelState = ( + datasourceState: unknown, + visualizationState: unknown, + visualizationType?: string + ) => { + if (attributes.state) { + const datasourceStates = { + ...attributes.state.datasourceStates, + [activeDatasourceId]: datasourceState, + }; + + const references = extractReferencesFromState({ + activeDatasources: Object.keys(datasourceStates).reduce( + (acc, datasourceId) => ({ + ...acc, + [datasourceId]: datasourceMap[datasourceId], + }), + {} + ), + datasourceStates: Object.fromEntries( + Object.entries(datasourceStates).map(([id, state]) => [id, { isLoading: false, state }]) + ), + visualizationState, + activeVisualization: visualizationType ? visualizationMap[visualizationType] : undefined, + }); + + const attrs = { + ...attributes, + state: { + ...attributes.state, + visualization: visualizationState, + datasourceStates, + }, + references, + visualizationType: visualizationType ?? attributes.visualizationType, + } as TypedLensByValueInput['attributes']; + + onUpdate(attrs); + } + }; + + const onUpdateSuggestion = (attrs: TypedLensByValueInput['attributes']) => { + const newAttributes = { + ...attributes, + ...attrs, + }; + onUpdate(newAttributes); + }; + + const Component = await getEditLensConfiguration(core, deps, visualizationMap, datasourceMap); + const ConfigPanel = ( + + ); + + // in case an element is given render the component in the container, + // otherwise a flyout will open + if (container) { + ReactDOM.render(ConfigPanel, container); + } else { + const handle = core.overlays.openFlyout( + toMountPoint( + React.cloneElement(ConfigPanel, { + closeFlyout: () => { + handle.close(); + }, + }), + { + theme$: core.theme.theme$, + } + ), + { + className: 'lnsConfigPanel__overlay', + size: 's', + 'data-test-subj': 'customizeLens', + type: 'push', + paddingSize: 'm', + hideCloseButton: true, + onClose: (overlayRef) => { + overlayRef.close(); + }, + outsideClickCloses: true, + } + ); + } +} diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_trigger.ts b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_trigger.ts new file mode 100644 index 0000000000000..41bd24e6a62ea --- /dev/null +++ b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_trigger.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 { i18n } from '@kbn/i18n'; +import type { Trigger } from '@kbn/ui-actions-plugin/public'; + +export const IN_APP_EMBEDDABLE_EDIT_TRIGGER = 'IN_APP_EMBEDDABLE_EDIT_TRIGGER'; +export const inAppEmbeddableEditTrigger: Trigger = { + id: IN_APP_EMBEDDABLE_EDIT_TRIGGER, + title: i18n.translate('xpack.lens.inAppEditTrigger.title', { + defaultMessage: 'In-app embeddable edit', + }), + description: i18n.translate('xpack.lens.inAppEditTrigger.description', { + defaultMessage: 'Triggers an in app flyout on the current embeddable', + }), +}; diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts new file mode 100644 index 0000000000000..e1eadf7a32660 --- /dev/null +++ b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { DefaultInspectorAdapters } from '@kbn/expressions-plugin/common'; +import type { EmbeddableOutput } from '@kbn/embeddable-plugin/public'; +import type { Observable } from 'rxjs'; +import type { TypedLensByValueInput } from '../../../embeddable/embeddable_component'; + +export interface LensChartLoadEvent { + /** + * Inspector adapters for the request + */ + adapters: Partial; + /** + * Observable of the lens embeddable output + */ + embeddableOutput$?: Observable; +} + +export interface InlineEditLensEmbeddableContext { + // attributes of the Lens embeddable + attributes: TypedLensByValueInput['attributes']; + // chart event, can be fetched from the onLoad embeddable callback + lensEvent: LensChartLoadEvent; + // callback which runs every time something changes in the dimension panel + onUpdate: (newAttributes: TypedLensByValueInput['attributes']) => void; + // optional onApply callback + onApply?: () => void; + // optional onCancel callback + onCancel?: () => void; + // custom container element, use in case you need to render outside a flyout + // in that case, the styling is responsibility of the consumer + container?: HTMLElement | null; +} diff --git a/x-pack/plugins/lens/readme.md b/x-pack/plugins/lens/readme.md index 764ff5f2df04f..fc2fd5df4c85a 100644 --- a/x-pack/plugins/lens/readme.md +++ b/x-pack/plugins/lens/readme.md @@ -271,3 +271,11 @@ Lens has a lot of UI elements – to make it easier to refer to them in issues o * **Suggestion panel** Panel to the bottom showing previews for suggestions on how to change the current chart ![Layout](./layout.png "Layout") + + +# Inline Editing of a Lens Embeddable + +If you have a Lens embeddable in your application and you want to allow inline editing you can do it with 3 ways: +- If you use a portable dashboard, the functionality is built in and you don't need to do anything +- If you don't have a portable dashboard then you can use UI actions to retrieve the inline editing component. For more information check out the example in `x-pack/examples/lens_embeddable_inline_editing_example`. +- The component is also exported from Lens start contract. Check the `EditLensConfigPanelApi`. This is advised to be used only when the 2 above cases can't be used. \ No newline at end of file diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_summary_flyout/risk_summary.test.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_summary_flyout/risk_summary.test.tsx index 1946c12aacdcf..b0ee36eff0747 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_summary_flyout/risk_summary.test.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_summary_flyout/risk_summary.test.tsx @@ -102,7 +102,9 @@ describe('RiskSummary', () => { const lensAttributes: LensAttributes = mockVisualizationEmbeddable.mock.calls[0][0].lensAttributes; - const datasourceLayers = Object.values(lensAttributes.state.datasourceStates.formBased.layers); + const datasourceLayers = Object.values( + lensAttributes.state.datasourceStates.formBased?.layers ?? {} + ); const firstColumn = Object.values(datasourceLayers[0].columns)[0]; expect(lensAttributes.state.query.query).toEqual('host.name: test'); @@ -126,7 +128,9 @@ describe('RiskSummary', () => { const lensAttributes: LensAttributes = mockVisualizationEmbeddable.mock.calls[0][0].lensAttributes; - const datasourceLayers = Object.values(lensAttributes.state.datasourceStates.formBased.layers); + const datasourceLayers = Object.values( + lensAttributes.state.datasourceStates.formBased?.layers ?? {} + ); const firstColumn = Object.values(datasourceLayers[0].columns)[0]; expect(lensAttributes.state.query.query).toEqual('user.name: test'); diff --git a/yarn.lock b/yarn.lock index 28057e7c10d95..9a5867e2361bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4986,6 +4986,9 @@ version "0.0.0" uid "" +"@kbn/lens-inline-editing-example-plugin@link:x-pack/examples/lens_embeddable_inline_editing_example": + + "@kbn/lens-plugin@link:x-pack/plugins/lens": version "0.0.0" uid "" From 35cccc29631e199979e6887eaf469444b285f637 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Fri, 5 Jan 2024 14:26:30 +0100 Subject: [PATCH 041/100] [Security Solution] OpenAPI linter (#171851) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Resolves: https://github.com/elastic/security-team/issues/8099** ## Summary This PR adds an a command to lint OpenAPI specs defined in Security Solution plugin. ## Details We have a number of OpenAPI specs defined in Security Solution plugin. While `@kbn/openapi-generator` package processes the specs and makes sure the specs are parsable and processable we don't have proper specs linter set up. This PR introduces OpenAPI specs linting by leveraging [Redocly CLI](https://github.com/Redocly/redocly-cli)'s `lint` command with a custom configuration placed in `@kbn/openapi-generator` package . Configuration includes reasonable best practices by using [built-in Redocly rules](https://redocly.com/docs/cli/rules/built-in-rules/). The lint utility fulfil the following requirements - Validates yaml files against OpenAPI specification. It supports `3.0` and `3.1`. - Validates `x-modify` property to have only `partial`, `required` or `requiredOptional` values. - Checks for reasonable best practices and displays a warning message when it's not met. Reasonable best practices are based on the [recommended ruleset](https://redocly.com/docs/cli/rules/recommended/#recommended-ruleset). The lint utility has been incorporated into the existing OpenAPI generator, and linting is performed before generation. ### Tool selection [Swagger CLI](https://github.com/APIDevTools/swagger-cli) is a well known tool to validate OpenAPI specs. On November 15th 2023 the repo has been archived with a message in README > ⚠️ Swagger CLI has been deprecated, due to the maintenance burnden of trying to keep up with expectations of a huge userbase with little to no pull requests or support. [Redocly CLI](https://redocly.com/redocly-cli/) covers all of the same functionality, and has more advanced linting with custom rules, and we highly recommend using that instead. They have conveniently provided a [migration guide](https://redocly.com/docs/cli/guides/migrate-from-swagger-cli/) for existing Swagger CLI users. Read the review of [Redocly CLI from APIs You Won't Hate](https://apisyouwonthate.com/blog/redocly-cli/). Taking it into account choice falls on **Redocly CLI**. ## How to test? Change directory to Security Solution plugin's root and run linting by using the following commands from Kibana root ```sh cd x-pack/plugins/security_solution yarn openapi:generate ``` --------- Co-authored-by: Georgii Gorbachev --- package.json | 1 + packages/kbn-openapi-generator/index.ts | 1 + .../redocly_linter/config.yaml | 27 + .../extra_linter_rules_plugin.js | 49 ++ packages/kbn-openapi-generator/src/cli.ts | 5 + .../src/openapi_generator.ts | 11 +- .../src/openapi_linter.ts | 47 ++ src/dev/license_checker/config.ts | 2 +- src/dev/yarn_deduplicate/index.ts | 2 +- .../osquery/scripts/openapi/generate.js | 2 + .../create_asset_criticality.schema.yaml | 3 +- .../delete_asset_criticality.schema.yaml | 3 +- .../get_asset_criticality.schema.yaml | 3 +- ...t_asset_criticality_privileges.schema.yaml | 3 +- .../get_asset_criticality_status.schema.yaml | 1 + x-pack/plugins/security_solution/package.json | 2 +- yarn.lock | 515 ++++++++++++++++-- 17 files changed, 620 insertions(+), 57 deletions(-) create mode 100644 packages/kbn-openapi-generator/redocly_linter/config.yaml create mode 100644 packages/kbn-openapi-generator/redocly_linter/extra_linter_rules_plugin.js create mode 100644 packages/kbn-openapi-generator/src/openapi_linter.ts diff --git a/package.json b/package.json index 0a4d9ebfcebdb..23e49b0d4cb35 100644 --- a/package.json +++ b/package.json @@ -1307,6 +1307,7 @@ "@octokit/rest": "^16.35.0", "@openpgp/web-stream-tools": "^0.0.10", "@parcel/watcher": "^2.1.0", + "@redocly/cli": "^1.6.0", "@storybook/addon-a11y": "^6.5.16", "@storybook/addon-actions": "^6.5.16", "@storybook/addon-controls": "^6.5.16", diff --git a/packages/kbn-openapi-generator/index.ts b/packages/kbn-openapi-generator/index.ts index eeaad5343dc9f..711ee4b6269d1 100644 --- a/packages/kbn-openapi-generator/index.ts +++ b/packages/kbn-openapi-generator/index.ts @@ -6,5 +6,6 @@ * Side Public License, v 1. */ +export * from './src/openapi_linter'; export * from './src/openapi_generator'; export * from './src/cli'; diff --git a/packages/kbn-openapi-generator/redocly_linter/config.yaml b/packages/kbn-openapi-generator/redocly_linter/config.yaml new file mode 100644 index 0000000000000..b423d9172b1c8 --- /dev/null +++ b/packages/kbn-openapi-generator/redocly_linter/config.yaml @@ -0,0 +1,27 @@ +# Recommended Redocly CLI ruleset https://redocly.com/docs/cli/rules/recommended/#recommended-ruleset +# Redocly CLI custom plugins https://redocly.com/docs/cli/custom-plugins/ +plugins: + - extra_linter_rules_plugin.js + +rules: + spec: error + spec-strict-refs: warn + no-path-trailing-slash: error + no-identical-paths: error + no-ambiguous-paths: warn + no-unresolved-refs: error + no-enum-type-mismatch: error + component-name-unique: error + path-declaration-must-exist: error + path-not-include-query: error + path-parameters-defined: warn + operation-description: warn + operation-2xx-response: error + operation-4xx-response: warn + operation-operationId: error + operation-operationId-unique: error + operation-summary: warn + operation-operationId-url-safe: error + operation-parameters-unique: error + boolean-parameter-prefixes: warn + extra-linter-rules-plugin/valid-x-modify: error diff --git a/packages/kbn-openapi-generator/redocly_linter/extra_linter_rules_plugin.js b/packages/kbn-openapi-generator/redocly_linter/extra_linter_rules_plugin.js new file mode 100644 index 0000000000000..caef408c366b2 --- /dev/null +++ b/packages/kbn-openapi-generator/redocly_linter/extra_linter_rules_plugin.js @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +const KNOWN_X_MODIFY_VALUES = ['partial', 'required', 'requiredOptional']; + +function ValidXModify() { + return { + any: { + leave(node, ctx) { + if (typeof node !== 'object' || !('x-modify' in node)) { + return; + } + + if (!KNOWN_X_MODIFY_VALUES.includes(node['x-modify'])) + ctx.report({ + message: `Only ${KNOWN_X_MODIFY_VALUES.join(', ')} can be used for x-modify`, + location: ctx.location.child('x-modify'), + }); + }, + }, + ref: { + leave(node, ctx) { + if (typeof node !== 'object' || !('x-modify' in node)) { + return; + } + + if (!KNOWN_X_MODIFY_VALUES.includes(node['x-modify'])) + ctx.report({ + message: `Only ${KNOWN_X_MODIFY_VALUES.join(', ')} can be used for x-modify`, + location: ctx.location.child('x-modify'), + }); + }, + }, + }; +} + +module.exports = { + id: 'extra-linter-rules-plugin', + rules: { + oas3: { + 'valid-x-modify': ValidXModify, + }, + }, +}; diff --git a/packages/kbn-openapi-generator/src/cli.ts b/packages/kbn-openapi-generator/src/cli.ts index 9eb91dd9bba94..6361c0a20de3b 100644 --- a/packages/kbn-openapi-generator/src/cli.ts +++ b/packages/kbn-openapi-generator/src/cli.ts @@ -31,6 +31,11 @@ export function runCli() { default: 'zod_operation_schema' as const, choices: AVAILABLE_TEMPLATES, }) + .option('skipLinting', { + describe: 'Whether linting should be skipped', + type: 'boolean', + default: false, + }) .showHelpOnFail(false), (argv) => { generate(argv).catch((err) => { diff --git a/packages/kbn-openapi-generator/src/openapi_generator.ts b/packages/kbn-openapi-generator/src/openapi_generator.ts index 539994a258126..60efd762dade7 100644 --- a/packages/kbn-openapi-generator/src/openapi_generator.ts +++ b/packages/kbn-openapi-generator/src/openapi_generator.ts @@ -17,6 +17,7 @@ import { fixEslint } from './lib/fix_eslint'; import { formatOutput } from './lib/format_output'; import { getGeneratedFilePath } from './lib/get_generated_file_path'; import { removeGenArtifacts } from './lib/remove_gen_artifacts'; +import { lint } from './openapi_linter'; import { getGenerationContext } from './parser/get_generation_context'; import type { OpenApiDocument } from './parser/openapi_types'; import { initTemplateService, TemplateName } from './template_service/template_service'; @@ -25,10 +26,18 @@ export interface GeneratorConfig { rootDir: string; sourceGlob: string; templateName: TemplateName; + skipLinting?: boolean; } export const generate = async (config: GeneratorConfig) => { - const { rootDir, sourceGlob, templateName } = config; + const { rootDir, sourceGlob, templateName, skipLinting } = config; + + if (!skipLinting) { + await lint({ + rootDir, + sourceGlob, + }); + } console.log(chalk.bold(`Generating API route schemas`)); console.log(chalk.bold(`Working directory: ${chalk.underline(rootDir)}`)); diff --git a/packages/kbn-openapi-generator/src/openapi_linter.ts b/packages/kbn-openapi-generator/src/openapi_linter.ts new file mode 100644 index 0000000000000..afd31a77bdee1 --- /dev/null +++ b/packages/kbn-openapi-generator/src/openapi_linter.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/* eslint-disable no-console */ + +import { resolve } from 'path'; +import globby from 'globby'; +import execa from 'execa'; +import chalk from 'chalk'; +import { REPO_ROOT } from '@kbn/repo-info'; + +export interface LinterConfig { + rootDir: string; + sourceGlob: string; +} + +export const lint = async (config: LinterConfig) => { + const { rootDir, sourceGlob } = config; + + const sourceFilesGlob = resolve(rootDir, sourceGlob); + const schemaPaths = await globby([sourceFilesGlob]); + + console.log(chalk.bold(`Linting API route schemas`)); + + try { + await execa( + './node_modules/.bin/redocly', + [ + 'lint', + '--config=packages/kbn-openapi-generator/redocly_linter/config.yaml', + ...schemaPaths, + ], + { + cwd: REPO_ROOT, + stderr: process.stderr, + stdout: process.stdout, + } + ); + } catch { + throw new Error('Linter failed'); + } +}; diff --git a/src/dev/license_checker/config.ts b/src/dev/license_checker/config.ts index 6ba5deb6408ac..db69bab07e1ea 100644 --- a/src/dev/license_checker/config.ts +++ b/src/dev/license_checker/config.ts @@ -73,7 +73,7 @@ export const LICENSE_ALLOWED = [ // The following list only applies to licenses that // we wanna allow in packages only used as dev dependencies -export const DEV_ONLY_LICENSE_ALLOWED = ['MPL-2.0']; +export const DEV_ONLY_LICENSE_ALLOWED = ['MPL-2.0', '(MPL-2.0 OR Apache-2.0)']; // there are some licenses which should not be globally allowed // but can be brought in on a per-package basis diff --git a/src/dev/yarn_deduplicate/index.ts b/src/dev/yarn_deduplicate/index.ts index 13c12ac5e91b7..1b1bade3b8b2c 100644 --- a/src/dev/yarn_deduplicate/index.ts +++ b/src/dev/yarn_deduplicate/index.ts @@ -16,7 +16,7 @@ const yarnLock = readFileSync(yarnLockFile, 'utf-8'); const output = fixDuplicates(yarnLock, { useMostCommon: false, excludeScopes: ['@types'], - excludePackages: ['axe-core', '@babel/types'], + excludePackages: ['axe-core', '@babel/types', 'csstype'], }); writeFileSync(yarnLockFile, output); diff --git a/x-pack/plugins/osquery/scripts/openapi/generate.js b/x-pack/plugins/osquery/scripts/openapi/generate.js index 018a965702c3e..35c099301e81c 100644 --- a/x-pack/plugins/osquery/scripts/openapi/generate.js +++ b/x-pack/plugins/osquery/scripts/openapi/generate.js @@ -17,4 +17,6 @@ generate({ rootDir: OSQUERY_ROOT, sourceGlob: './**/*.schema.yaml', templateName: 'zod_operation_schema', + // TODO: Fix lint errors + skipLinting: true, }); diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/create_asset_criticality.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/create_asset_criticality.schema.yaml index bb5e682155064..cc8c980809f9b 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/create_asset_criticality.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/create_asset_criticality.schema.yaml @@ -12,6 +12,7 @@ servers: paths: /internal/asset_criticality: post: + operationId: AssetCriticalityCreateRecord summary: Create Criticality Record requestBody: required: true @@ -27,4 +28,4 @@ paths: schema: $ref: './common.schema.yaml#/components/schemas/AssetCriticalityRecord' '400': - description: Invalid request \ No newline at end of file + description: Invalid request diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/delete_asset_criticality.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/delete_asset_criticality.schema.yaml index fbdb4feb19e52..cada6a62fcaac 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/delete_asset_criticality.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/delete_asset_criticality.schema.yaml @@ -12,6 +12,7 @@ servers: paths: /internal/asset_criticality: delete: + operationId: AssetCriticalityDeleteRecord summary: Delete Criticality Record parameters: - $ref: './common.schema.yaml#/components/parameters/id_value' @@ -20,4 +21,4 @@ paths: '200': description: Successful response '400': - description: Invalid request \ No newline at end of file + description: Invalid request diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality.schema.yaml index 1411f2a08734f..777666daccb2f 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality.schema.yaml @@ -12,6 +12,7 @@ servers: paths: /internal/asset_criticality: get: + operationId: AssetCriticalityGetRecord summary: Get Criticality Record parameters: - $ref: './common.schema.yaml#/components/parameters/id_value' @@ -26,4 +27,4 @@ paths: '400': description: Invalid request '404': - description: Criticality record not found \ No newline at end of file + description: Criticality record not found diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality_privileges.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality_privileges.schema.yaml index b877b90efca94..6f1734262c667 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality_privileges.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality_privileges.schema.yaml @@ -12,6 +12,7 @@ servers: paths: /internal/asset_criticality/privileges: get: + operationId: AssetCriticalityGetPrivileges summary: Get Asset Criticality Privileges responses: '200': @@ -26,4 +27,4 @@ paths: ".asset-criticality.asset-criticality-*": read: true write: false - has_all_required: false \ No newline at end of file + has_all_required: false diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality_status.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality_status.schema.yaml index a5a6b50354688..a62450cbcff4d 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality_status.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality_status.schema.yaml @@ -12,6 +12,7 @@ servers: paths: /internal/asset_criticality/status: get: + operationId: AssetCriticalityGetStatus summary: Get Asset Criticality Status responses: '200': diff --git a/x-pack/plugins/security_solution/package.json b/x-pack/plugins/security_solution/package.json index 5f0613c3e89b8..3d9effa5983bf 100644 --- a/x-pack/plugins/security_solution/package.json +++ b/x-pack/plugins/security_solution/package.json @@ -29,4 +29,4 @@ "openapi:generate:debug": "node --inspect-brk scripts/openapi/generate", "openapi:bundle": "node scripts/openapi/bundle" } -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index 9a5867e2361bc..21b560fc24e86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2010,6 +2010,13 @@ resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43" integrity sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ== +"@emotion/is-prop-valid@1.2.1", "@emotion/is-prop-valid@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz#23116cf1ed18bfeac910ec6436561ecb1a3885cc" + integrity sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw== + dependencies: + "@emotion/memoize" "^0.8.1" + "@emotion/is-prop-valid@^0.8.8": version "0.8.8" resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" @@ -2017,13 +2024,6 @@ dependencies: "@emotion/memoize" "0.7.4" -"@emotion/is-prop-valid@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz#23116cf1ed18bfeac910ec6436561ecb1a3885cc" - integrity sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw== - dependencies: - "@emotion/memoize" "^0.8.1" - "@emotion/jest@^11.11.0": version "11.11.0" resolved "https://registry.yarnpkg.com/@emotion/jest/-/jest-11.11.0.tgz#4d64b33052308739dcdd7396fd2bc902f7244f82" @@ -2123,6 +2123,11 @@ resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== +"@emotion/unitless@0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.0.tgz#a4a36e9cbdc6903737cd20d38033241e1b8833db" + integrity sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw== + "@emotion/unitless@^0.8.1": version "0.8.1" resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.1.tgz#182b5a4704ef8ad91bde93f7a860a88fd92c79a3" @@ -2295,6 +2300,11 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.46.0.tgz#3f7802972e8b6fe3f88ed1aabc74ec596c456db6" integrity sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA== +"@exodus/schemasafe@^1.0.0-rc.2": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@exodus/schemasafe/-/schemasafe-1.3.0.tgz#731656abe21e8e769a7f70a4d833e6312fe59b7f" + integrity sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw== + "@fastify/busboy@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.0.0.tgz#f22824caff3ae506b18207bad4126dbc6ccdb6b8" @@ -7475,6 +7485,54 @@ unbzip2-stream "1.4.3" yargs "17.7.2" +"@redocly/ajv@^8.11.0": + version "8.11.0" + resolved "https://registry.yarnpkg.com/@redocly/ajv/-/ajv-8.11.0.tgz#2fad322888dc0113af026e08fceb3e71aae495ae" + integrity sha512-9GWx27t7xWhDIR02PA18nzBdLcKQRgc46xNQvjFkrYk4UOmvKhJ/dawwiX0cCOeetN5LcaaiqQbVOWYK62SGHw== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +"@redocly/cli@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@redocly/cli/-/cli-1.6.0.tgz#d3f6c8d6822eead487c2cb814d131e17d05c961f" + integrity sha512-0naVFJGR2tVcpMIHSFRr2HAoyy70qMqDAP6kXcnOdkGkwLRJ8s/5n1STwsym/yZwNkhrt2M0cKT6KAMlTUeCeg== + dependencies: + "@redocly/openapi-core" "1.6.0" + chokidar "^3.5.1" + colorette "^1.2.0" + core-js "^3.32.1" + get-port-please "^3.0.1" + glob "^7.1.6" + handlebars "^4.7.6" + mobx "^6.0.4" + node-fetch "^2.6.1" + react "^17.0.0 || ^18.2.0" + react-dom "^17.0.0 || ^18.2.0" + redoc "~2.1.3" + semver "^7.5.2" + simple-websocket "^9.0.0" + styled-components "^6.0.7" + yargs "17.0.1" + +"@redocly/openapi-core@1.6.0", "@redocly/openapi-core@^1.0.0-rc.2": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@redocly/openapi-core/-/openapi-core-1.6.0.tgz#09aee5e21a9cbad08f3230ced16685d043a9b197" + integrity sha512-oao6Aey4peLKfagzWGb6N7OBI6CoDWEP4ka/XjrUNZw+UoKVVg3hVBXW4Vr3CJ2O8j6wEa2i+Lbb92VQQsoxwg== + dependencies: + "@redocly/ajv" "^8.11.0" + "@types/node" "^14.11.8" + colorette "^1.2.0" + js-levenshtein "^1.1.6" + js-yaml "^4.1.0" + lodash.isequal "^4.5.0" + minimatch "^5.0.1" + node-fetch "^2.6.1" + pluralize "^8.0.0" + yaml-ast-parser "0.0.43" + "@redux-saga/core@^1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@redux-saga/core/-/core-1.1.3.tgz#3085097b57a4ea8db5528d58673f20ce0950f6a4" @@ -9564,6 +9622,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== +"@types/json-schema@^7.0.7": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + "@types/json-stable-stringify@^1.0.32": version "1.0.32" resolved "https://registry.yarnpkg.com/@types/json-stable-stringify/-/json-stable-stringify-1.0.32.tgz#121f6917c4389db3923640b2e68de5fa64dda88e" @@ -9797,7 +9860,7 @@ dependencies: "@types/node" "*" -"@types/node@*", "@types/node@20.10.5", "@types/node@>= 8", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@>=18.0.0", "@types/node@^10.1.0", "@types/node@^14.0.10 || ^16.0.0", "@types/node@^14.14.20 || ^16.0.0", "@types/node@^18.11.18", "@types/node@^18.17.5": +"@types/node@*", "@types/node@20.10.5", "@types/node@>= 8", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@>=18.0.0", "@types/node@^10.1.0", "@types/node@^14.0.10 || ^16.0.0", "@types/node@^14.11.8", "@types/node@^14.14.20 || ^16.0.0", "@types/node@^18.11.18", "@types/node@^18.17.5": version "20.10.5" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.5.tgz#47ad460b514096b7ed63a1dae26fad0914ed3ab2" integrity sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw== @@ -10234,6 +10297,11 @@ "@types/react-native" "*" csstype "^2.2.0" +"@types/stylis@4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@types/stylis/-/stylis-4.2.0.tgz#199a3f473f0c3a6f6e4e1b17cdbc967f274bdc6b" + integrity sha512-n4sx2bqL0mW1tvDf/loQ+aMX7GQD3lc3fkCMC55VFNDu/vBOabO+LTIeXKM14xK0ppk5TUGcWRjiSpIlUpghKw== + "@types/superagent@*": version "3.8.4" resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-3.8.4.tgz#24a5973c7d1a9c024b4bbda742a79267c33fb86a" @@ -13039,7 +13107,7 @@ cheerio@^1.0.0-rc.12, cheerio@^1.0.0-rc.3: parse5 "^7.0.0" parse5-htmlparser2-tree-adapter "^7.0.0" -chokidar@3.5.3, chokidar@^2.1.2, chokidar@^2.1.8, chokidar@^3.4.0, chokidar@^3.4.1, chokidar@^3.4.2, chokidar@^3.5.3: +chokidar@3.5.3, chokidar@^2.1.2, chokidar@^2.1.8, chokidar@^3.4.0, chokidar@^3.4.1, chokidar@^3.4.2, chokidar@^3.5.1, chokidar@^3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -13141,10 +13209,10 @@ classnames@2.2.6: resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== -classnames@^2.2.6, classnames@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" - integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw== +classnames@^2.2.6, classnames@^2.3.1, classnames@^2.3.2: + version "2.5.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" + integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== clean-css@^4.2.3: version "4.2.3" @@ -13320,10 +13388,10 @@ cloneable-readable@^1.0.0: process-nextick-args "^2.0.0" readable-stream "^2.3.5" -clsx@^1.0.4, clsx@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" - integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== +clsx@^1.0.4, clsx@^1.1.0, clsx@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" + integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== co@^4.6.0: version "4.6.0" @@ -13418,10 +13486,10 @@ colord@^2.9.1, colord@^2.9.2: resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1" integrity sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ== -colorette@^1.2.1, colorette@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" - integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== +colorette@^1.2.0, colorette@^1.2.1, colorette@^1.2.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" + integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== colorette@^2.0.10, colorette@^2.0.14: version "2.0.19" @@ -13764,10 +13832,10 @@ core-js@^2.4.0, core-js@^2.5.0, core-js@^2.6.9: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2" integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A== -core-js@^3.0.4, core-js@^3.34.0, core-js@^3.6.5, core-js@^3.8.2, core-js@^3.8.3: - version "3.34.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.34.0.tgz#5705e6ad5982678612e96987d05b27c6c7c274a5" - integrity sha512-aDdvlDder8QmY91H88GzNi9EtQi2TjvQhpCX6B1v/dAZHU1AuLgHvRh54RiOerpEhEW46Tkf+vgAViB/CWC0ag== +core-js@^3.0.4, core-js@^3.32.1, core-js@^3.34.0, core-js@^3.6.5, core-js@^3.8.2, core-js@^3.8.3: + version "3.35.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.35.0.tgz#58e651688484f83c34196ca13f099574ee53d6b4" + integrity sha512-ntakECeqg81KqMueeGJ79Q5ZgQNR+6eaE8sxGCx62zMbAIj65q+uYvatToew3m6eAGdU4gNZwpZ34NMe4GYswg== core-util-is@1.0.2, core-util-is@^1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -14025,10 +14093,10 @@ css-select@^5.1.0: domutils "^3.0.1" nth-check "^2.0.1" -css-to-react-native@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.0.0.tgz#62dbe678072a824a689bcfee011fc96e02a7d756" - integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ== +css-to-react-native@3.2.0, css-to-react-native@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.2.0.tgz#cdd8099f71024e149e4f6fe17a7d46ecd55f1e32" + integrity sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ== dependencies: camelize "^1.0.0" css-color-keywords "^1.0.0" @@ -14145,6 +14213,11 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" +csstype@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" + integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== + csstype@^2.2.0, csstype@^2.5.5, csstype@^2.5.7, csstype@^2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.7.tgz#20b0024c20b6718f4eda3853a1f5a1cce7f5e4a5" @@ -14685,6 +14758,11 @@ decimal.js@^10.4.1: resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.1.tgz#be75eeac4a2281aace80c1a8753587c27ef053e7" integrity sha512-F29o+vci4DodHYT9UrR5IEbfBw9pE5eSapIJdTqXK5+6hq+t8VRxwQyKlW2i+KDKFkkJQRvFyI/QXD83h8LyQw== +decko@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decko/-/decko-1.2.0.tgz#fd43c735e967b8013306884a56fbe665996b6817" + integrity sha512-m8FnyHXV1QX+S1cl+KPFDIl6NMkxtKsy6+U/aYyjrOqWMuwAwYWu7ePqrsUHtDR5Y8Yk2pi/KIDSgF+vT4cPOQ== + decode-uri-component@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" @@ -15299,6 +15377,11 @@ domhandler@^5.0.1, domhandler@^5.0.2, domhandler@^5.0.3: dependencies: domelementtype "^2.3.0" +dompurify@^2.2.8: + version "2.4.7" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.7.tgz#277adeb40a2c84be2d42a8bcd45f582bfa4d0cfc" + integrity sha512-kxxKlPEDa6Nc5WJi+qRgPbOAbgTpSULL+vI3NUXsZMlkJxTqYI9wg5ZTay2sFrdZRWHPWNi+EdAhcJf81WtoMQ== + domutils@^2.0.0, domutils@^2.5.2, domutils@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" @@ -15931,6 +16014,11 @@ es6-map@^0.1.5: es6-symbol "~3.1.1" event-emitter "~0.3.5" +es6-promise@^3.2.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" + integrity sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg== + es6-promise@^4.2.8: version "4.2.8" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" @@ -16445,7 +16533,7 @@ eventemitter2@6.4.7: resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.7.tgz#a7f6c4d7abf28a14c1ef3442f21cb306a054271d" integrity sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg== -eventemitter3@^4.0.0, eventemitter3@^4.0.4: +eventemitter3@^4.0.0, eventemitter3@^4.0.4, eventemitter3@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== @@ -17184,6 +17272,11 @@ for-in@^1.0.2: resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= +foreach@^2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.6.tgz#87bcc8a1a0e74000ff2bf9802110708cfb02eb6e" + integrity sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg== + foreground-child@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" @@ -17602,6 +17695,11 @@ get-package-type@^0.1.0: resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== +get-port-please@^3.0.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/get-port-please/-/get-port-please-3.1.1.tgz#2556623cddb4801d823c0a6a15eec038abb483be" + integrity sha512-3UBAyM3u4ZBVYDsxOQfJDxEa6XTbpBDrOjp4mf7ExFRt5BKs/QywQQiJsh2B+hxcZLSapWqCRvElUe8DnKcFHA== + get-port@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" @@ -18097,7 +18195,7 @@ handle-thing@^2.0.0: resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== -handlebars@4.7.8, handlebars@^4.7.7: +handlebars@4.7.8, handlebars@^4.7.6, handlebars@^4.7.7: version "4.7.8" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== @@ -18697,6 +18795,11 @@ http-signature@~1.3.6: jsprim "^2.0.2" sshpk "^1.14.1" +http2-client@^1.2.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/http2-client/-/http2-client-1.3.5.tgz#20c9dc909e3cc98284dd20af2432c524086df181" + integrity sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA== + http2-wrapper@^1.0.0-beta.5.2: version "1.0.0-beta.5.2" resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.0-beta.5.2.tgz#8b923deb90144aea65cf834b016a340fc98556f3" @@ -20616,6 +20719,13 @@ json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== +json-pointer@0.6.2, json-pointer@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/json-pointer/-/json-pointer-0.6.2.tgz#f97bd7550be5e9ea901f8c9264c9d436a22a93cd" + integrity sha512-vLWcKbOaXlO+jvRy4qNd+TI1QUPZzfJj1tpJ3vAXDych5XJf93ftpUKe5pKCrzyIIwgBJcOcCVRUfqQP25afBw== + dependencies: + foreach "^2.0.4" + json-schema-to-ts@^2.9.1: version "2.9.1" resolved "https://registry.yarnpkg.com/json-schema-to-ts/-/json-schema-to-ts-2.9.1.tgz#0e055b787587477abdb7e880c874efad3dba7779" @@ -21587,6 +21697,11 @@ lru-queue@0.1: dependencies: es5-ext "~0.10.2" +lunr@^2.3.9: + version "2.3.9" + resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" + integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow== + luxon@^1.25.0: version "1.28.1" resolved "https://registry.yarnpkg.com/luxon/-/luxon-1.28.1.tgz#528cdf3624a54506d710290a2341aa8e6e6c61b0" @@ -21732,6 +21847,11 @@ marge@^1.0.1: dependencies: yargs "^3.15.0" +mark.js@^8.11.1: + version "8.11.1" + resolved "https://registry.yarnpkg.com/mark.js/-/mark.js-8.11.1.tgz#180f1f9ebef8b0e638e4166ad52db879beb2ffc5" + integrity sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ== + markdown-escapes@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.1.tgz#1994df2d3af4811de59a6714934c2b2292734518" @@ -21767,6 +21887,11 @@ markdown-table@^2.0.0: dependencies: repeat-string "^1.0.0" +marked@^4.0.15: + version "4.3.0" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3" + integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A== + material-colors@^1.2.1: version "1.2.5" resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.5.tgz#5292593e6754cb1bcc2b98030e4e0d6a3afc9ea1" @@ -22456,6 +22581,23 @@ ml-tree-similarity@^1.0.0: binary-search "^1.3.5" num-sort "^2.0.0" +mobx-react-lite@^3.4.0: + version "3.4.3" + resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-3.4.3.tgz#3a4c22c30bfaa8b1b2aa48d12b2ba811c0947ab7" + integrity sha512-NkJREyFTSUXR772Qaai51BnE1voWx56LOL80xG7qkZr6vo8vEaLF3sz1JNUVh+rxmUzxYaqOhfuxTfqUh0FXUg== + +mobx-react@^7.2.0: + version "7.6.0" + resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-7.6.0.tgz#ebf0456728a9bd2e5c24fdcf9b36e285a222a7d6" + integrity sha512-+HQUNuh7AoQ9ZnU6c4rvbiVVl+wEkb9WqYsVDzGLng+Dqj1XntHu79PvEWKtSMoMj67vFp/ZPXcElosuJO8ckA== + dependencies: + mobx-react-lite "^3.4.0" + +mobx@^6.0.4: + version "6.12.0" + resolved "https://registry.yarnpkg.com/mobx/-/mobx-6.12.0.tgz#72b2685ca5af031aaa49e77a4d76ed67fcbf9135" + integrity sha512-Mn6CN6meXEnMa0a5u6a5+RKrqRedHBhZGd15AWLk9O6uFY4KYHzImdt8JI8WODo1bjTSRnwXhJox+FCUZhCKCQ== + mocha-junit-reporter@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-2.0.2.tgz#d521689b651dc52f52044739f8ffb368be415731" @@ -22937,6 +23079,13 @@ node-emoji@^1.10.0: dependencies: lodash.toarray "^4.4.0" +node-fetch-h2@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz#c6188325f9bd3d834020bf0f2d6dc17ced2241ac" + integrity sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg== + dependencies: + http2-client "^1.2.5" + node-fetch@^1.0.1, node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.6.7: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" @@ -23052,6 +23201,13 @@ node-preload@^0.2.1: dependencies: process-on-spawn "^1.0.0" +node-readfiles@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/node-readfiles/-/node-readfiles-0.2.0.tgz#dbbd4af12134e2e635c245ef93ffcf6f60673a5d" + integrity sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA== + dependencies: + es6-promise "^3.2.1" + node-releases@^2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" @@ -23240,6 +23396,52 @@ nyc@15.1.0, nyc@^15.1.0: test-exclude "^6.0.0" yargs "^15.0.2" +oas-kit-common@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/oas-kit-common/-/oas-kit-common-1.0.8.tgz#6d8cacf6e9097967a4c7ea8bcbcbd77018e1f535" + integrity sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ== + dependencies: + fast-safe-stringify "^2.0.7" + +oas-linter@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/oas-linter/-/oas-linter-3.2.2.tgz#ab6a33736313490659035ca6802dc4b35d48aa1e" + integrity sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ== + dependencies: + "@exodus/schemasafe" "^1.0.0-rc.2" + should "^13.2.1" + yaml "^1.10.0" + +oas-resolver@^2.5.6: + version "2.5.6" + resolved "https://registry.yarnpkg.com/oas-resolver/-/oas-resolver-2.5.6.tgz#10430569cb7daca56115c915e611ebc5515c561b" + integrity sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ== + dependencies: + node-fetch-h2 "^2.3.0" + oas-kit-common "^1.0.8" + reftools "^1.1.9" + yaml "^1.10.0" + yargs "^17.0.1" + +oas-schema-walker@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/oas-schema-walker/-/oas-schema-walker-1.1.5.tgz#74c3cd47b70ff8e0b19adada14455b5d3ac38a22" + integrity sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ== + +oas-validator@^5.0.8: + version "5.0.8" + resolved "https://registry.yarnpkg.com/oas-validator/-/oas-validator-5.0.8.tgz#387e90df7cafa2d3ffc83b5fb976052b87e73c28" + integrity sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw== + dependencies: + call-me-maybe "^1.0.1" + oas-kit-common "^1.0.8" + oas-linter "^3.2.2" + oas-resolver "^2.5.6" + oas-schema-walker "^1.1.5" + reftools "^1.1.9" + should "^13.2.1" + yaml "^1.10.0" + object-assign@4.X, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -23477,6 +23679,14 @@ openai@^4.17.0, openai@^4.24.1: node-fetch "^2.6.7" web-streams-polyfill "^3.2.1" +openapi-sampler@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/openapi-sampler/-/openapi-sampler-1.4.0.tgz#c133cad6250481f2ec7e48b16eb70062adb514c0" + integrity sha512-3FKJQCHAMG9T7RsRy9u5Ft4ERPq1QQmn77C8T3OSofYL9uur59AqychvQ0YQKijrqRwIkAbzkh+nQnAE3gjMVA== + dependencies: + "@types/json-schema" "^7.0.7" + json-pointer "0.6.2" + openapi-types@^10.0.0: version "10.0.0" resolved "https://registry.yarnpkg.com/openapi-types/-/openapi-types-10.0.0.tgz#0debbf663b2feed0322030b5b7c9080804076934" @@ -24086,6 +24296,11 @@ pend@~1.2.0: resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= +perfect-scrollbar@^1.5.5: + version "1.5.5" + resolved "https://registry.yarnpkg.com/perfect-scrollbar/-/perfect-scrollbar-1.5.5.tgz#41a211a2fb52a7191eff301432134ea47052b27f" + integrity sha512-dzalfutyP3e/FOpdlhVryN4AJ5XDVauVWxybSkLZmakFE2sS3y3pc4JnSprw8tGmHvkaG5Edr5T7LBTZ+WWU2g== + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -24335,7 +24550,7 @@ polished@^3.7.2: dependencies: "@babel/runtime" "^7.12.5" -polished@^4.2.2: +polished@^4.1.3, polished@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/polished/-/polished-4.2.2.tgz#2529bb7c3198945373c52e34618c8fe7b1aa84d1" integrity sha512-Sz2Lkdxz6F2Pgnpi9U5Ng/WdWAUZxmHrNPoVlm3aAemxoy2Qy7LGjQg4uf8qKelDAUW94F4np3iH2YPf2qefcQ== @@ -24650,15 +24865,7 @@ postcss-values-parser@^6.0.2: is-url-superb "^4.0.0" quote-unquote "^1.0.0" -postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.26, postcss@^7.0.32, postcss@^7.0.36, postcss@^7.0.5, postcss@^7.0.6: - version "7.0.39" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" - integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== - dependencies: - picocolors "^0.2.1" - source-map "^0.6.1" - -postcss@^8.4.14, postcss@^8.4.23, postcss@^8.4.31: +postcss@8.4.31, postcss@^8.4.14, postcss@^8.4.23, postcss@^8.4.31: version "8.4.31" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== @@ -24667,6 +24874,14 @@ postcss@^8.4.14, postcss@^8.4.23, postcss@^8.4.31: picocolors "^1.0.0" source-map-js "^1.0.2" +postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.26, postcss@^7.0.32, postcss@^7.0.36, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.39" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" + integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== + dependencies: + picocolors "^0.2.1" + source-map "^0.6.1" + potpack@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/potpack/-/potpack-2.0.0.tgz#61f4dd2dc4b3d5e996e3698c0ec9426d0e169104" @@ -24810,7 +25025,12 @@ printj@~1.1.0: resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222" integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ== -prismjs@^1.22.0, prismjs@~1.27.0: +prismjs@^1.22.0, prismjs@^1.27.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12" + integrity sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q== + +prismjs@~1.27.0: version "1.27.0" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.27.0.tgz#bb6ee3138a0b438a3653dd4d6ce0cc6510a45057" integrity sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA== @@ -24918,7 +25138,7 @@ prompts@^2.0.1, prompts@^2.4.0, prompts@~2.4.2: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@15.x, prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.0, prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@15.x, prop-types@^15.0.0, prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.0, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -25184,6 +25404,11 @@ querystringify@^2.1.1: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + queue-tick@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142" @@ -25421,6 +25646,14 @@ react-docgen@^5.0.0: node-dir "^0.1.10" strip-indent "^3.0.0" +"react-dom@^17.0.0 || ^18.2.0": + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" + integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.0" + react-dom@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" @@ -25824,6 +26057,14 @@ react-syntax-highlighter@^15.3.1: prismjs "^1.22.0" refractor "^3.2.0" +react-tabs@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/react-tabs/-/react-tabs-4.3.0.tgz#9f4db0fd209ba4ab2c1e78993ff964435f84af62" + integrity sha512-2GfoG+f41kiBIIyd3gF+/GRCCYtamC8/2zlAcD8cqQmqI9Q+YVz7fJLHMmU9pXDVYYHpJeCgUSBJju85vu5q8Q== + dependencies: + clsx "^1.1.0" + prop-types "^15.5.0" + "react-test-renderer@^16.8.0 || ^17.0.0", react-test-renderer@^17.0.0, react-test-renderer@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-17.0.2.tgz#4cd4ae5ef1ad5670fc0ef776e8cc7e1231d9866c" @@ -25903,6 +26144,13 @@ react-window@^1.8.9: "@babel/runtime" "^7.0.0" memoize-one ">=3.1.1 <6" +"react@^17.0.0 || ^18.2.0": + version "18.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" + integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== + dependencies: + loose-envify "^1.1.0" + react@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" @@ -26105,6 +26353,33 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +redoc@~2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/redoc/-/redoc-2.1.3.tgz#612c9fed744993d5fc99cbf39fe9056bd1034fa5" + integrity sha512-d7F9qLLxaiFW4GC03VkwlX9wuRIpx9aiIIf3o6mzMnqPfhxrn2IRKGndrkJeVdItgCfmg9jXZiFEowm60f1meQ== + dependencies: + "@redocly/openapi-core" "^1.0.0-rc.2" + classnames "^2.3.1" + decko "^1.2.0" + dompurify "^2.2.8" + eventemitter3 "^4.0.7" + json-pointer "^0.6.2" + lunr "^2.3.9" + mark.js "^8.11.1" + marked "^4.0.15" + mobx-react "^7.2.0" + openapi-sampler "^1.3.1" + path-browserify "^1.0.1" + perfect-scrollbar "^1.5.5" + polished "^4.1.3" + prismjs "^1.27.0" + prop-types "^15.7.2" + react-tabs "^4.3.0" + slugify "~1.4.7" + stickyfill "^1.1.1" + swagger2openapi "^7.0.6" + url-template "^2.0.8" + reduce-reducers@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/reduce-reducers/-/reduce-reducers-0.4.3.tgz#8e052618801cd8fc2714b4915adaa8937eb6d66c" @@ -26179,6 +26454,11 @@ refractor@^3.2.0, refractor@^3.6.0: parse-entities "^2.0.0" prismjs "~1.27.0" +reftools@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/reftools/-/reftools-1.1.9.tgz#e16e19f662ccd4648605312c06d34e5da3a2b77e" + integrity sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w== + regedit@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/regedit/-/regedit-5.0.0.tgz#7ec444ef027cc704e104fae00586f84752291116" @@ -27039,6 +27319,13 @@ scheduler@^0.20.2: loose-envify "^1.1.0" object-assign "^4.1.1" +scheduler@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" + integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== + dependencies: + loose-envify "^1.1.0" + schema-utils@2.7.0, schema-utils@^2.0.0, schema-utils@^2.0.1, schema-utils@^2.5.0, schema-utils@^2.6.5, schema-utils@^2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" @@ -27323,7 +27610,7 @@ shallow-equal@^3.1.0: resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-3.1.0.tgz#e7a54bac629c7f248eff6c2f5b63122ba4320bec" integrity sha512-pfVOw8QZIXpMbhBWvzBISicvToTiM5WBF1EeAUZDDSb5Dt29yl4AYbyywbJFSEsRUMr7gJaxqCdr4L3tQf9wVg== -shallowequal@^1.1.0: +shallowequal@1.1.0, shallowequal@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== @@ -27389,6 +27676,50 @@ shelljs@^0.8.5: interpret "^1.0.0" rechoir "^0.6.2" +should-equal@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/should-equal/-/should-equal-2.0.0.tgz#6072cf83047360867e68e98b09d71143d04ee0c3" + integrity sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA== + dependencies: + should-type "^1.4.0" + +should-format@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/should-format/-/should-format-3.0.3.tgz#9bfc8f74fa39205c53d38c34d717303e277124f1" + integrity sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q== + dependencies: + should-type "^1.3.0" + should-type-adaptors "^1.0.1" + +should-type-adaptors@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz#401e7f33b5533033944d5cd8bf2b65027792e27a" + integrity sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA== + dependencies: + should-type "^1.3.0" + should-util "^1.0.0" + +should-type@^1.3.0, should-type@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/should-type/-/should-type-1.4.0.tgz#0756d8ce846dfd09843a6947719dfa0d4cff5cf3" + integrity sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ== + +should-util@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/should-util/-/should-util-1.0.1.tgz#fb0d71338f532a3a149213639e2d32cbea8bcb28" + integrity sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g== + +should@^13.2.1: + version "13.2.3" + resolved "https://registry.yarnpkg.com/should/-/should-13.2.3.tgz#96d8e5acf3e97b49d89b51feaa5ae8d07ef58f10" + integrity sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ== + dependencies: + should-equal "^2.0.0" + should-format "^3.0.3" + should-type "^1.4.0" + should-type-adaptors "^1.0.1" + should-util "^1.0.0" + side-channel@^1.0.2, side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -27453,6 +27784,17 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" +simple-websocket@^9.0.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/simple-websocket/-/simple-websocket-9.1.0.tgz#91cbb39eafefbe7e66979da6c639109352786a7f" + integrity sha512-8MJPnjRN6A8UCp1I+H/dSFyjwJhp6wta4hsVRhjf8w9qBHRzxYt14RaOcjvQnhD1N4yKOddEjflwMnQM4VtXjQ== + dependencies: + debug "^4.3.1" + queue-microtask "^1.2.2" + randombytes "^2.1.0" + readable-stream "^3.6.0" + ws "^7.4.2" + sinon@^7.4.2: version "7.5.0" resolved "https://registry.yarnpkg.com/sinon/-/sinon-7.5.0.tgz#e9488ea466070ea908fd44a3d6478fd4923c67ec" @@ -27518,6 +27860,11 @@ slide@~1.1.3: resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= +slugify@~1.4.7: + version "1.4.7" + resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.4.7.tgz#e42359d505afd84a44513280868e31202a79a628" + integrity sha512-tf+h5W1IrjNm/9rKKj0JU2MDMruiopx0jjVA5zCdBtcGjfp0+c5rHw/zADLC3IeKlGHtVbHtpfzvYA0OYT+HKg== + smart-buffer@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" @@ -28060,6 +28407,11 @@ stats-lite@^2.2.0: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= +stickyfill@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stickyfill/-/stickyfill-1.1.1.tgz#39413fee9d025c74a7e59ceecb23784cc0f17f02" + integrity sha512-GCp7vHAfpao+Qh/3Flh9DXEJ/qSi0KJwJw6zYlZOtRYXWUIpMM6mC2rIep/dK8RQqwW0KxGJIllmjPIBOGN8AA== + store2@^2.12.0: version "2.12.0" resolved "https://registry.yarnpkg.com/store2/-/store2-2.12.0.tgz#e1f1b7e1a59b6083b2596a8d067f6ee88fd4d3cf" @@ -28398,6 +28750,21 @@ styled-components@^5.1.0: shallowequal "^1.1.0" supports-color "^5.5.0" +styled-components@^6.0.7: + version "6.1.6" + resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-6.1.6.tgz#c75c4f994136545b3bcc11608db5363710b78c0e" + integrity sha512-DgTLULSC29xpabJ24bbn1+hulU6vvGFQf4RPwBOJrm8WJFnN42yXpo5voBt3jDSJBa5tBd1L6PqswJjQ0wRKdg== + dependencies: + "@emotion/is-prop-valid" "1.2.1" + "@emotion/unitless" "0.8.0" + "@types/stylis" "4.2.0" + css-to-react-native "3.2.0" + csstype "3.1.2" + postcss "8.4.31" + shallowequal "1.1.0" + stylis "4.3.1" + tslib "2.5.0" + stylehacks@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.0.tgz#a40066490ca0caca04e96c6b02153ddc39913520" @@ -28473,6 +28840,11 @@ stylis@4.2.0: resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== +stylis@4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.1.tgz#ed8a9ebf9f76fe1e12d462f5cc3c4c980b23a7eb" + integrity sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ== + stylus-lookup@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/stylus-lookup/-/stylus-lookup-5.0.1.tgz#3c4d116c3b1e8e1a8169c0d9cd20e608595560f4" @@ -28592,6 +28964,23 @@ svgo@^2.7.0, svgo@^2.8.0: picocolors "^1.0.0" stable "^0.1.8" +swagger2openapi@^7.0.6: + version "7.0.8" + resolved "https://registry.yarnpkg.com/swagger2openapi/-/swagger2openapi-7.0.8.tgz#12c88d5de776cb1cbba758994930f40ad0afac59" + integrity sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g== + dependencies: + call-me-maybe "^1.0.1" + node-fetch "^2.6.1" + node-fetch-h2 "^2.3.0" + node-readfiles "^0.2.0" + oas-kit-common "^1.0.8" + oas-resolver "^2.5.6" + oas-schema-walker "^1.1.5" + oas-validator "^5.0.8" + reftools "^1.1.9" + yaml "^1.10.0" + yargs "^17.0.1" + symbol-observable@^1.0.4, symbol-observable@^1.1.0, symbol-observable@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" @@ -29272,6 +29661,11 @@ tslib@2.3.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== +tslib@2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" + integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== + tslib@^1.10.0, tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -29892,6 +30286,11 @@ url-parse@^1.5.10, url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" +url-template@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21" + integrity sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw== + url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" @@ -31197,10 +31596,10 @@ ws@8.14.2, ws@>=8.14.2, ws@^8.2.3, ws@^8.4.2, ws@^8.9.0: resolved "https://registry.yarnpkg.com/ws/-/ws-8.14.2.tgz#6c249a806eb2db7a20d26d51e7709eab7b2e6c7f" integrity sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g== -ws@^7.3.1: - version "7.5.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" - integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== +ws@^7.3.1, ws@^7.4.2: + version "7.5.9" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" + integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== x-default-browser@^0.4.0: version "0.4.0" @@ -31320,6 +31719,11 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yaml-ast-parser@0.0.43: + version "0.0.43" + resolved "https://registry.yarnpkg.com/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz#e8a23e6fb4c38076ab92995c5dca33f3d3d7c9bb" + integrity sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A== + yaml-language-server-parser@^0.1.0: version "0.1.3" resolved "https://registry.yarnpkg.com/yaml-language-server-parser/-/yaml-language-server-parser-0.1.3.tgz#f0e9082068291c7c330eefa1f3c9f1b4c3c54183" @@ -31376,7 +31780,20 @@ yargs@16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@17.7.2, yargs@^17.2.1, yargs@^17.3.1, yargs@^17.4.0, yargs@^17.7.1, yargs@^17.7.2: +yargs@17.0.1: + version "17.0.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.0.1.tgz#6a1ced4ed5ee0b388010ba9fd67af83b9362e0bb" + integrity sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yargs@17.7.2, yargs@^17.0.1, yargs@^17.2.1, yargs@^17.3.1, yargs@^17.4.0, yargs@^17.7.1, yargs@^17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== From d458b5382fdbf29e7f35a35fe2792aa86f4d6c4c Mon Sep 17 00:00:00 2001 From: "Eyo O. Eyo" <7893459+eokoneyo@users.noreply.github.com> Date: Fri, 5 Jan 2024 14:35:09 +0100 Subject: [PATCH 042/100] Remove legacy kibana react code editor (#171047) ## Summary This PR removes the legacy kibana react code-editor, alongside replacing all import declarations of this legacy component to the one offered by shared-ux, i.e import declaration source of `'@kbn/kibana-react/public'` is switched to `@kbn/code-editor`. Also in this PR an helper for writing jest tests has been included through the package `@kbn/code-editor-mock`, this would facilitate mocking the editor, especially given that the code editor leverages couple of APIs that are aren't included by default in jsdom, among them, `matchMedia`, `ResizeObserver`. The provided mock is sufficient for most use cases and can be setup in any package within kibana as a [`node_module` mock](https://jestjs.io/docs/manual-mocks#mocking-node-modules) without having to repeatedly manually mock the editor within individual test files. An example for how this might be done can be found here https://github.com/elastic/kibana/pull/171047/commits/ec5ba253688e952c6e601fb6e07de860e2a25c3a ### Checklist - [x] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .github/CODEOWNERS | 3 +- .../public/editor/expression_editor.tsx | 2 +- examples/expressions_explorer/tsconfig.json | 1 + package.json | 3 +- .../components/field_input/code_editor.tsx | 5 +- .../components/field_input/tsconfig.json | 2 +- packages/kbn-monaco/index.ts | 10 +- packages/kbn-monaco/src/monaco_imports.ts | 14 +++ packages/kbn-monaco/src/typings.d.ts | 12 +++ .../src/text_based_languages_editor.tsx | 3 +- packages/kbn-text-based-editor/tsconfig.json | 3 +- packages/kbn-ui-shared-deps-src/BUILD.bazel | 1 + .../kbn-ui-shared-deps-src/src/definitions.js | 1 + packages/kbn-ui-shared-deps-src/src/entry.js | 1 + .../src/utils/get_render_cell_value.test.tsx | 3 +- .../shared-ux/code_editor/impl/BUILD.bazel | 37 +++++++ .../code_editor/{ => impl}/README.mdx | 0 .../__snapshots__/code_editor.test.tsx.snap | 34 ++++++- .../{ => impl}/code_editor.stories.tsx | 0 .../{ => impl}/code_editor.test.tsx | 20 +++- .../code_editor/{ => impl}/code_editor.tsx | 0 .../code_editor/{ => impl}/editor.styles.ts | 0 packages/shared-ux/code_editor/impl/index.tsx | 83 ++++++++++++++++ .../code_editor/{ => impl}/jest.config.js | 2 +- .../code_editor/{ => impl}/kibana.jsonc | 0 .../{ => impl}/languages/constants.ts | 0 .../{ => impl}/languages/css/constants.ts | 0 .../{ => impl}/languages/css/index.ts | 0 .../{ => impl}/languages/css/language.ts | 5 +- .../{ => impl}/languages/grok/constants.ts | 0 .../{ => impl}/languages/grok/index.ts | 0 .../languages/grok/language.test.ts | 0 .../{ => impl}/languages/grok/language.ts | 0 .../languages/handlebars/constants.ts | 0 .../{ => impl}/languages/handlebars/index.ts | 0 .../languages/handlebars/language.ts | 0 .../{ => impl}/languages/hjson/constants.ts | 0 .../{ => impl}/languages/hjson/index.ts | 0 .../{ => impl}/languages/hjson/language.ts | 0 .../code_editor/{ => impl}/languages/index.ts | 0 .../languages/markdown/constants.ts | 0 .../{ => impl}/languages/markdown/index.ts | 0 .../languages/markdown}/language.ts | 5 +- .../{ => impl}/languages/yaml/constants.ts | 0 .../{ => impl}/languages/yaml/index.ts | 0 .../languages/yaml}/language.ts | 5 +- .../code_editor/{ => impl}/mocks/storybook.ts | 0 .../code_editor/{ => impl}/package.json | 0 .../{ => impl}/placeholder_widget.ts | 0 .../{ => impl}/register_languages.ts | 0 .../code_editor/{ => impl}/remeasure_fonts.ts | 0 .../code_editor/{ => impl}/tsconfig.json | 5 +- .../shared-ux/code_editor/mocks/README.md | 23 +++++ .../code_editor/mocks/code_editor_mock.tsx | 28 ++++++ .../code_editor/{ => mocks}/index.ts | 2 +- .../code_editor/mocks/jest_helper.ts | 15 +-- .../shared-ux/code_editor/mocks/kibana.jsonc | 5 + .../monaco_mock/index.tsx} | 96 +++++++++++-------- .../shared-ux/code_editor/mocks/package.json | 6 ++ .../shared-ux/code_editor/mocks/tsconfig.json | 24 +++++ .../components/field/field.test.tsx | 1 + .../components/field/field_code_editor.tsx | 3 +- src/plugins/advanced_settings/tsconfig.json | 2 + .../components/actions/inspect_button.tsx | 7 +- src/plugins/data/tsconfig.json | 3 +- .../data_view_editor/public/shared_imports.ts | 9 +- src/plugins/data_view_editor/tsconfig.json | 1 + .../client_integration/helpers/jest.mocks.tsx | 4 +- .../public/shared_imports.ts | 8 +- .../data_view_field_editor/tsconfig.json | 1 + .../field_editor/field_editor.test.tsx | 4 +- .../components/field_editor/field_editor.tsx | 3 +- .../data_view_management/tsconfig.json | 1 + src/plugins/es_ui_shared/kibana.jsonc | 3 +- .../components/json_editor/json_editor.tsx | 2 +- src/plugins/es_ui_shared/tsconfig.json | 2 +- .../components/details/req_code_viewer.tsx | 3 +- src/plugins/inspector/tsconfig.json | 3 +- .../kibana_react/public/code_editor/README.md | 12 --- .../public/code_editor/code_editor_field.tsx | 38 -------- .../kibana_react/public/code_editor/index.tsx | 66 ------------- src/plugins/kibana_react/public/index.ts | 12 --- .../url_template_editor.stories.tsx | 2 +- .../url_template_editor.tsx | 3 +- src/plugins/kibana_react/tsconfig.json | 1 - .../components/expression_input/constants.ts | 2 +- .../expression_input/expression_input.tsx | 2 +- src/plugins/presentation_util/tsconfig.json | 3 +- .../object_view/components/inspect.tsx | 2 +- .../saved_objects_management/tsconfig.json | 1 + src/plugins/unified_doc_viewer/kibana.jsonc | 2 +- .../doc_viewer_source/source.test.tsx | 1 + .../json_code_editor_common.tsx | 2 +- src/plugins/unified_doc_viewer/tsconfig.json | 4 +- .../filter_editor/filter_editor.test.tsx | 4 +- .../filter_editor/filter_editor.tsx | 2 +- src/plugins/unified_search/tsconfig.json | 3 +- .../public/components/controls/raw_json.tsx | 2 +- src/plugins/vis_default_editor/tsconfig.json | 1 + .../components/timelion_expression_input.tsx | 3 +- src/plugins/vis_types/timelion/tsconfig.json | 1 + .../application/components/markdown_editor.js | 3 +- .../components/panel_config/markdown.tsx | 2 +- .../vis_types/timeseries/tsconfig.json | 1 + .../public/components/vega_vis_editor.tsx | 2 +- .../vega_inspector/components/spec_viewer.tsx | 2 +- src/plugins/vis_types/vega/tsconfig.json | 1 + tsconfig.base.json | 6 +- typings/index.d.ts | 5 - .../testing_embedded_lens/public/app.tsx | 3 +- .../testing_embedded_lens/tsconfig.json | 1 + .../cytoscape_example_data.stories.tsx | 2 +- .../settings_form/form_row_setting.tsx | 2 +- .../shared/monaco_code_editor/index.tsx | 2 +- x-pack/plugins/apm/tsconfig.json | 5 +- .../uis/arguments/editor.tsx | 2 +- .../uis/datasources/essql.js | 2 +- .../canvas_plugin_src/uis/views/markdown.js | 2 +- x-pack/plugins/canvas/tsconfig.json | 1 + .../control_settings/index.test.tsx | 3 +- .../control_yaml_view/index.test.tsx | 2 +- .../components/control_yaml_view/index.tsx | 2 +- .../components/policy_settings/index.test.tsx | 1 + .../public/test/test_provider.tsx | 2 +- x-pack/plugins/cloud_defend/tsconfig.json | 3 +- .../findings_flyout/json_tab.tsx | 2 +- .../vulnerability_finding_flyout.test.tsx | 1 + .../vulnerability_json_tab.tsx | 2 +- .../cloud_security_posture/tsconfig.json | 4 +- .../components/json_editor/json_editor.tsx | 2 +- x-pack/plugins/data_visualizer/tsconfig.json | 1 + .../sync_rules/advanced_sync_rules.tsx | 2 +- .../pipelines/ml_inference/test_pipeline.tsx | 2 +- .../shared/api_key/metadata_form.tsx | 2 +- .../api_key/security_privileges_form.tsx | 2 +- .../plugins/enterprise_search/tsconfig.json | 1 + .../components/import_complete_view.tsx | 3 +- x-pack/plugins/file_upload/tsconfig.json | 1 + .../package_policy_input_var_field.tsx | 2 +- .../sections/debug/components/code_block.tsx | 2 +- .../edit_output_flyout/index.test.tsx | 2 +- .../yaml_code_editor_with_placeholder.tsx | 3 +- x-pack/plugins/fleet/tsconfig.json | 1 + .../custom_patterns_input.js | 2 +- .../components/event_input/event_input.js | 2 +- .../components/pattern_input/pattern_input.js | 3 +- x-pack/plugins/grokdebugger/tsconfig.json | 1 + .../create_enrich_policy.test.tsx | 4 +- .../home/enrich_policies.test.tsx | 4 +- .../index_details_page.test.tsx | 4 +- .../template_create.test.tsx | 4 +- .../template_edit.test.tsx | 4 +- .../component_template_create.test.tsx | 4 +- .../component_template_edit.test.tsx | 8 +- .../helpers/mappings_editor.helpers.tsx | 4 +- .../helpers/setup_environment.tsx | 4 +- .../load_mappings_provider.test.tsx | 4 +- .../components/wizard_steps/step_aliases.tsx | 2 +- .../components/wizard_steps/step_settings.tsx | 2 +- .../details_flyout/policy_details_flyout.tsx | 2 +- .../details_page_settings_content.tsx | 2 +- x-pack/plugins/index_management/tsconfig.json | 1 + .../ingest_pipelines_create.test.tsx | 4 +- .../ingest_pipelines_create_from_csv.test.tsx | 4 +- .../pipeline_processors_editor.helpers.tsx | 4 +- .../__jest__/processors/processor.helpers.tsx | 4 +- .../__jest__/test_pipeline.helpers.tsx | 4 +- .../load_from_json/modal_provider.test.tsx | 4 +- .../pipelines_preview.tsx | 2 +- .../ingest_pipelines/public/shared_imports.ts | 3 +- x-pack/plugins/ingest_pipelines/tsconfig.json | 1 + .../formula/editor/formula_editor.tsx | 3 +- x-pack/plugins/lens/tsconfig.json | 2 + .../pipeline_editor/pipeline_editor.js | 2 +- x-pack/plugins/logstash/tsconfig.json | 1 + .../components/tile_request_tab.tsx | 2 +- .../components/vector_tile_inspector.tsx | 2 +- x-pack/plugins/maps/tsconfig.json | 1 + .../components/processor_configuration.tsx | 2 +- .../ml_inference/components/test_pipeline.tsx | 2 +- .../shared/on_failure_configuration.tsx | 2 +- .../create_analytics_advanced_editor.tsx | 2 +- .../runtime_mappings_editor.tsx | 2 +- .../ml_job_editor/ml_job_editor.tsx | 2 +- .../pipeline_details.tsx | 2 +- x-pack/plugins/ml/tsconfig.json | 1 + .../chat/chat_prompt_editor_function.tsx | 2 +- .../observability_ai_assistant/tsconfig.json | 3 +- .../plugins/osquery/public/editor/index.tsx | 2 +- x-pack/plugins/osquery/tsconfig.json | 3 +- .../public/application/components/editor.tsx | 2 +- .../components/output_pane/context_tab.tsx | 2 +- .../components/output_pane/parameters_tab.tsx | 2 +- x-pack/plugins/painless_lab/tsconfig.json | 1 + .../public/__jest__/setup_environment.tsx | 21 +--- .../runtime_fields/public/shared_imports.ts | 8 +- x-pack/plugins/runtime_fields/tsconfig.json | 2 + .../api_keys/api_keys_grid/api_key_flyout.tsx | 3 +- .../edit_role_mapping_page.test.tsx | 1 + .../json_rule_editor.test.tsx | 3 +- .../rule_editor_panel/json_rule_editor.tsx | 3 +- .../rule_editor_panel.test.tsx | 1 + .../es/index_privilege_form.test.tsx | 4 +- .../privileges/es/index_privilege_form.tsx | 2 +- .../privileges/es/index_privileges.test.tsx | 1 + x-pack/plugins/security/tsconfig.json | 6 +- .../components/api_key/metadata_form.tsx | 2 +- .../api_key/security_privileges_form.tsx | 2 +- .../plugins/serverless_search/tsconfig.json | 1 + .../client_integration/helpers/mocks.tsx | 19 +--- .../type_settings/hdfs_settings.tsx | 2 +- .../steps/step_settings.tsx | 2 +- x-pack/plugins/snapshot_restore/tsconfig.json | 2 + .../expression/es_query_expression.test.tsx | 12 ++- .../expression/es_query_expression.tsx | 2 +- .../es_query/expression/expression.test.tsx | 4 +- x-pack/plugins/stack_alerts/tsconfig.json | 1 + .../__mocks__/@kbn/code-editor/index.tsx | 8 ++ .../connector_types/bedrock/params.test.tsx | 12 --- .../cases_webhook/webhook_connectors.test.tsx | 12 --- .../cases_webhook/webhook_params.test.tsx | 17 +--- .../d3security/params.test.tsx | 12 --- .../es_index/es_index_params.test.tsx | 13 --- .../connector_types/openai/params.test.tsx | 12 --- .../opsgenie/create_alert/index.test.tsx | 13 --- .../create_alert/json_editor.test.tsx | 13 --- .../connector_types/opsgenie/params.test.tsx | 12 --- .../tines/tines_params.test.tsx | 12 --- .../connector_types/torq/torq_params.test.tsx | 13 --- .../webhook/webhook_params.test.tsx | 13 --- x-pack/plugins/stack_connectors/tsconfig.json | 2 + .../__mocks__/@kbn/code-editor/index.ts | 8 ++ .../monitor_add_edit/fields/code_editor.tsx | 2 +- .../fields/request_body_field.test.tsx | 26 +---- .../fields/source_field.test.tsx | 17 ---- .../monitor_add_page.test.tsx | 17 ---- .../monitor_edit_page.test.tsx | 17 ---- x-pack/plugins/synthetics/tsconfig.json | 5 +- .../advanced_pivot_editor.tsx | 2 +- .../advanced_runtime_mappings_editor.tsx | 2 +- .../advanced_source_editor.tsx | 2 +- .../filter_agg/components/editor_form.tsx | 2 +- x-pack/plugins/transform/tsconfig.json | 3 +- .../public/application/code_editor.mock.tsx | 35 ------- ...son_editor_with_message_variables.test.tsx | 10 +- .../json_editor_with_message_variables.tsx | 2 +- .../plugins/triggers_actions_ui/tsconfig.json | 4 +- ...ics_edit_policy_extension_wrapper.test.tsx | 4 +- .../watch_create_json_page.test.tsx | 4 +- .../watch_create_threshold_page.test.tsx | 4 +- .../watch_edit_page.test.tsx | 4 +- .../json_watch_edit/json_watch_edit_form.tsx | 2 +- .../json_watch_edit_simulate.tsx | 2 +- .../action_fields/webhook_action_fields.tsx | 2 +- x-pack/plugins/watcher/tsconfig.json | 1 + yarn.lock | 6 +- 256 files changed, 671 insertions(+), 696 deletions(-) create mode 100644 packages/kbn-monaco/src/typings.d.ts create mode 100644 packages/shared-ux/code_editor/impl/BUILD.bazel rename packages/shared-ux/code_editor/{ => impl}/README.mdx (100%) rename packages/shared-ux/code_editor/{ => impl}/__snapshots__/code_editor.test.tsx.snap (88%) rename packages/shared-ux/code_editor/{ => impl}/code_editor.stories.tsx (100%) rename packages/shared-ux/code_editor/{ => impl}/code_editor.test.tsx (94%) rename packages/shared-ux/code_editor/{ => impl}/code_editor.tsx (100%) rename packages/shared-ux/code_editor/{ => impl}/editor.styles.ts (100%) create mode 100644 packages/shared-ux/code_editor/impl/index.tsx rename packages/shared-ux/code_editor/{ => impl}/jest.config.js (94%) rename packages/shared-ux/code_editor/{ => impl}/kibana.jsonc (100%) rename packages/shared-ux/code_editor/{ => impl}/languages/constants.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/languages/css/constants.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/languages/css/index.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/languages/css/language.ts (64%) rename packages/shared-ux/code_editor/{ => impl}/languages/grok/constants.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/languages/grok/index.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/languages/grok/language.test.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/languages/grok/language.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/languages/handlebars/constants.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/languages/handlebars/index.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/languages/handlebars/language.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/languages/hjson/constants.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/languages/hjson/index.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/languages/hjson/language.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/languages/index.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/languages/markdown/constants.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/languages/markdown/index.ts (100%) rename packages/shared-ux/code_editor/{languages/yaml => impl/languages/markdown}/language.ts (64%) rename packages/shared-ux/code_editor/{ => impl}/languages/yaml/constants.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/languages/yaml/index.ts (100%) rename packages/shared-ux/code_editor/{languages/markdown => impl/languages/yaml}/language.ts (63%) rename packages/shared-ux/code_editor/{ => impl}/mocks/storybook.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/package.json (100%) rename packages/shared-ux/code_editor/{ => impl}/placeholder_widget.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/register_languages.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/remeasure_fonts.ts (100%) rename packages/shared-ux/code_editor/{ => impl}/tsconfig.json (80%) create mode 100644 packages/shared-ux/code_editor/mocks/README.md create mode 100644 packages/shared-ux/code_editor/mocks/code_editor_mock.tsx rename packages/shared-ux/code_editor/{ => mocks}/index.ts (84%) rename src/plugins/kibana_react/public/code_editor/code_editor.tsx => packages/shared-ux/code_editor/mocks/jest_helper.ts (58%) create mode 100644 packages/shared-ux/code_editor/mocks/kibana.jsonc rename packages/shared-ux/code_editor/{code_editor.test.helpers.tsx => mocks/monaco_mock/index.tsx} (66%) create mode 100644 packages/shared-ux/code_editor/mocks/package.json create mode 100644 packages/shared-ux/code_editor/mocks/tsconfig.json delete mode 100644 src/plugins/kibana_react/public/code_editor/README.md delete mode 100644 src/plugins/kibana_react/public/code_editor/code_editor_field.tsx delete mode 100644 src/plugins/kibana_react/public/code_editor/index.tsx create mode 100644 x-pack/plugins/stack_connectors/__mocks__/@kbn/code-editor/index.tsx create mode 100644 x-pack/plugins/synthetics/__mocks__/@kbn/code-editor/index.ts delete mode 100644 x-pack/plugins/triggers_actions_ui/public/application/code_editor.mock.tsx diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4dae217dce6ad..d2d3d6b0f1b33 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -86,7 +86,8 @@ x-pack/test/cloud_integration/plugins/saml_provider @elastic/kibana-core x-pack/plugins/cloud_integrations/cloud_links @elastic/kibana-core x-pack/plugins/cloud @elastic/kibana-core x-pack/plugins/cloud_security_posture @elastic/kibana-cloud-security-posture -packages/shared-ux/code_editor @elastic/appex-sharedux +packages/shared-ux/code_editor/impl @elastic/appex-sharedux +packages/shared-ux/code_editor/mocks @elastic/appex-sharedux packages/kbn-code-owners @elastic/appex-qa packages/kbn-coloring @elastic/kibana-visualizations packages/kbn-config @elastic/kibana-core diff --git a/examples/expressions_explorer/public/editor/expression_editor.tsx b/examples/expressions_explorer/public/editor/expression_editor.tsx index c940a21fada27..998a9e486ba19 100644 --- a/examples/expressions_explorer/public/editor/expression_editor.tsx +++ b/examples/expressions_explorer/public/editor/expression_editor.tsx @@ -7,7 +7,7 @@ */ import React from 'react'; -import { CodeEditor } from '@kbn/kibana-react-plugin/public'; +import { CodeEditor } from '@kbn/code-editor'; interface Props { value: string; diff --git a/examples/expressions_explorer/tsconfig.json b/examples/expressions_explorer/tsconfig.json index 717a797173597..b75817c68be7c 100644 --- a/examples/expressions_explorer/tsconfig.json +++ b/examples/expressions_explorer/tsconfig.json @@ -22,5 +22,6 @@ "@kbn/i18n", "@kbn/i18n-react", "@kbn/core-ui-settings-browser", + "@kbn/code-editor", ] } diff --git a/package.json b/package.json index 23e49b0d4cb35..22ac585845216 100644 --- a/package.json +++ b/package.json @@ -192,7 +192,8 @@ "@kbn/cloud-links-plugin": "link:x-pack/plugins/cloud_integrations/cloud_links", "@kbn/cloud-plugin": "link:x-pack/plugins/cloud", "@kbn/cloud-security-posture-plugin": "link:x-pack/plugins/cloud_security_posture", - "@kbn/code-editor": "link:packages/shared-ux/code_editor", + "@kbn/code-editor": "link:packages/shared-ux/code_editor/impl", + "@kbn/code-editor-mock": "link:packages/shared-ux/code_editor/mocks", "@kbn/coloring": "link:packages/kbn-coloring", "@kbn/config": "link:packages/kbn-config", "@kbn/config-mocks": "link:packages/kbn-config-mocks", diff --git a/packages/kbn-management/settings/components/field_input/code_editor.tsx b/packages/kbn-management/settings/components/field_input/code_editor.tsx index 3f46778917fdd..ac1ea672d8a15 100644 --- a/packages/kbn-management/settings/components/field_input/code_editor.tsx +++ b/packages/kbn-management/settings/components/field_input/code_editor.tsx @@ -15,11 +15,12 @@ import React, { useCallback } from 'react'; import { monaco, XJsonLang } from '@kbn/monaco'; + import { CodeEditor as KibanaReactCodeEditor, - MarkdownLang, type CodeEditorProps as KibanaReactCodeEditorProps, -} from '@kbn/kibana-react-plugin/public'; + MarkdownLang, +} from '@kbn/code-editor'; type Props = Pick; type Options = KibanaReactCodeEditorProps['options']; diff --git a/packages/kbn-management/settings/components/field_input/tsconfig.json b/packages/kbn-management/settings/components/field_input/tsconfig.json index bb4c6b4aa57d0..d971549abb2d4 100644 --- a/packages/kbn-management/settings/components/field_input/tsconfig.json +++ b/packages/kbn-management/settings/components/field_input/tsconfig.json @@ -19,7 +19,6 @@ "@kbn/management-settings-types", "@kbn/management-settings-field-definition", "@kbn/monaco", - "@kbn/kibana-react-plugin", "@kbn/management-settings-utilities", "@kbn/i18n-react", "@kbn/i18n", @@ -30,5 +29,6 @@ "@kbn/core-i18n-browser", "@kbn/core-analytics-browser-mocks", "@kbn/core-ui-settings-browser", + "@kbn/code-editor", ] } diff --git a/packages/kbn-monaco/index.ts b/packages/kbn-monaco/index.ts index 2ebb05bd0e393..e2e3c32d9d0fd 100644 --- a/packages/kbn-monaco/index.ts +++ b/packages/kbn-monaco/index.ts @@ -8,7 +8,15 @@ import './src/register_globals'; -export { monaco } from './src/monaco_imports'; +export { + monaco, + cssConf, + cssLanguage, + markdownConf, + markdownLanguage, + yamlConf, + yamlLanguage, +} from './src/monaco_imports'; export { XJsonLang } from './src/xjson'; export { SQLLang } from './src/sql'; export { ESQL_LANG_ID, ESQL_THEME_ID, ESQLLang } from './src/esql'; diff --git a/packages/kbn-monaco/src/monaco_imports.ts b/packages/kbn-monaco/src/monaco_imports.ts index 9da2a3f4562f3..cebdb7ffa1045 100644 --- a/packages/kbn-monaco/src/monaco_imports.ts +++ b/packages/kbn-monaco/src/monaco_imports.ts @@ -28,4 +28,18 @@ import 'monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution. import 'monaco-editor/esm/vs/basic-languages/xml/xml.contribution.js'; // Needed for basic xml support import 'monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution'; // Needed for yaml support +// config for supported base languages +export { + conf as cssConf, + language as cssLanguage, +} from 'monaco-editor/esm/vs/basic-languages/css/css'; +export { + conf as markdownConf, + language as markdownLanguage, +} from 'monaco-editor/esm/vs/basic-languages/markdown/markdown'; +export { + conf as yamlConf, + language as yamlLanguage, +} from 'monaco-editor/esm/vs/basic-languages/yaml/yaml'; + export { monaco }; diff --git a/packages/kbn-monaco/src/typings.d.ts b/packages/kbn-monaco/src/typings.d.ts new file mode 100644 index 0000000000000..64301b9a59683 --- /dev/null +++ b/packages/kbn-monaco/src/typings.d.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +// Monaco languages support +declare module 'monaco-editor/esm/vs/basic-languages/markdown/markdown'; +declare module 'monaco-editor/esm/vs/basic-languages/css/css'; +declare module 'monaco-editor/esm/vs/basic-languages/yaml/yaml'; diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx index 24966c78960bb..3546fcec41af4 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx @@ -39,8 +39,7 @@ import { EuiOutsideClickDetector, EuiToolTip, } from '@elastic/eui'; -import { CodeEditor } from '@kbn/kibana-react-plugin/public'; -import type { CodeEditorProps } from '@kbn/kibana-react-plugin/public'; +import { CodeEditor, CodeEditorProps } from '@kbn/code-editor'; import { textBasedLanguagedEditorStyles, diff --git a/packages/kbn-text-based-editor/tsconfig.json b/packages/kbn-text-based-editor/tsconfig.json index 72240c8aa060d..1c71fc544155d 100644 --- a/packages/kbn-text-based-editor/tsconfig.json +++ b/packages/kbn-text-based-editor/tsconfig.json @@ -24,7 +24,8 @@ "@kbn/expressions-plugin", "@kbn/data-views-plugin", "@kbn/index-management-plugin", - "@kbn/visualization-utils" + "@kbn/visualization-utils", + "@kbn/code-editor", ], "exclude": [ "target/**/*", diff --git a/packages/kbn-ui-shared-deps-src/BUILD.bazel b/packages/kbn-ui-shared-deps-src/BUILD.bazel index cd97c193f9f86..9e62a7418f153 100644 --- a/packages/kbn-ui-shared-deps-src/BUILD.bazel +++ b/packages/kbn-ui-shared-deps-src/BUILD.bazel @@ -35,6 +35,7 @@ webpack_cli( "//packages/kbn-peggy-loader", "//packages/shared-ux/error_boundary", "//packages/kbn-rison", + "//packages/shared-ux/code_editor/impl:code_editor", ], output_dir = True, args = [ diff --git a/packages/kbn-ui-shared-deps-src/src/definitions.js b/packages/kbn-ui-shared-deps-src/src/definitions.js index 9ae258dca6bc8..7480303087b6c 100644 --- a/packages/kbn-ui-shared-deps-src/src/definitions.js +++ b/packages/kbn-ui-shared-deps-src/src/definitions.js @@ -98,6 +98,7 @@ const externals = { classnames: '__kbnSharedDeps__.Classnames', '@tanstack/react-query': '__kbnSharedDeps__.ReactQuery', '@tanstack/react-query-devtools': '__kbnSharedDeps__.ReactQueryDevtools', + '@kbn/code-editor': '__kbnSharedDeps__.KbnCodeEditor', }; module.exports = { distDir, jsFilename, cssDistFilename, externals }; diff --git a/packages/kbn-ui-shared-deps-src/src/entry.js b/packages/kbn-ui-shared-deps-src/src/entry.js index 6ba856cbbc2d1..d0585d0cacc04 100644 --- a/packages/kbn-ui-shared-deps-src/src/entry.js +++ b/packages/kbn-ui-shared-deps-src/src/entry.js @@ -74,3 +74,4 @@ export const History = require('history'); export const Classnames = require('classnames'); export const ReactQuery = require('@tanstack/react-query'); export const ReactQueryDevtools = require('@tanstack/react-query-devtools'); +export const KbnCodeEditor = require('@kbn/code-editor'); diff --git a/packages/kbn-unified-data-table/src/utils/get_render_cell_value.test.tsx b/packages/kbn-unified-data-table/src/utils/get_render_cell_value.test.tsx index 7db7ffedfdecf..c59acdc815389 100644 --- a/packages/kbn-unified-data-table/src/utils/get_render_cell_value.test.tsx +++ b/packages/kbn-unified-data-table/src/utils/get_render_cell_value.test.tsx @@ -13,7 +13,8 @@ import { findTestSubject } from '@elastic/eui/lib/test'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { getRenderCellValueFn } from './get_render_cell_value'; import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; -import { CodeEditorProps, KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { CodeEditorProps } from '@kbn/code-editor'; import { buildDataTableRecord } from '@kbn/discover-utils'; import type { EsHitRecord } from '@kbn/discover-utils/types'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; diff --git a/packages/shared-ux/code_editor/impl/BUILD.bazel b/packages/shared-ux/code_editor/impl/BUILD.bazel new file mode 100644 index 0000000000000..ad571cb379afd --- /dev/null +++ b/packages/shared-ux/code_editor/impl/BUILD.bazel @@ -0,0 +1,37 @@ +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") + +SRCS = glob( + [ + "**/*.ts", + "**/*.tsx", + ], + exclude = [ + "**/test_helpers.ts", + "**/*.config.js", + "**/*.mock.*", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/mocks/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +BUNDLER_DEPS = [ + "@npm//react", + "@npm//tslib", + "@npm//react-monaco-editor", + "@npm//react-resize-detector", +] + +js_library( + name = "code_editor", + package_name = "@kbn/code-editor", + srcs = SRCS + ["package.json"], + deps = BUNDLER_DEPS, + visibility = ["//visibility:public"], +) diff --git a/packages/shared-ux/code_editor/README.mdx b/packages/shared-ux/code_editor/impl/README.mdx similarity index 100% rename from packages/shared-ux/code_editor/README.mdx rename to packages/shared-ux/code_editor/impl/README.mdx diff --git a/packages/shared-ux/code_editor/__snapshots__/code_editor.test.tsx.snap b/packages/shared-ux/code_editor/impl/__snapshots__/code_editor.test.tsx.snap similarity index 88% rename from packages/shared-ux/code_editor/__snapshots__/code_editor.test.tsx.snap rename to packages/shared-ux/code_editor/impl/__snapshots__/code_editor.test.tsx.snap index 790a4f05f8c50..4fb960f82cc7d 100644 --- a/packages/shared-ux/code_editor/__snapshots__/code_editor.test.tsx.snap +++ b/packages/shared-ux/code_editor/impl/__snapshots__/code_editor.test.tsx.snap @@ -290,7 +290,7 @@ exports[` is rendered 1`] = ` - is rendered 1`] = `