From a7211fc34ae290b10a331ea7cbfe34d53f75cacf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20C=C3=B4t=C3=A9?= Date: Wed, 4 Sep 2024 13:43:16 -0400 Subject: [PATCH 01/99] Optimize ES Query's use of dataViews and searchSourceClient by only loading when it's a search source query (#192079) In this PR, I'm optimizing the use of dataViews and searchSourceClient within the ES Query rule by only loading those services whenever the rule uses a search source query and skip loading when it's ES DSL or KQL. --- .../server/rule_types/es_query/executor.test.ts | 3 ++- .../server/rule_types/es_query/executor.ts | 6 ++---- .../es_query/lib/fetch_search_source_query.test.ts | 10 +++++----- .../es_query/lib/fetch_search_source_query.ts | 12 +++++++----- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/x-pack/plugins/stack_alerts/server/rule_types/es_query/executor.test.ts b/x-pack/plugins/stack_alerts/server/rule_types/es_query/executor.test.ts index c138b8d867017..8d1302ebcec01 100644 --- a/x-pack/plugins/stack_alerts/server/rule_types/es_query/executor.test.ts +++ b/x-pack/plugins/stack_alerts/server/rule_types/es_query/executor.test.ts @@ -189,7 +189,8 @@ describe('es_query executor', () => { params: { ...defaultProps, searchType: 'searchSource' }, latestTimestamp: undefined, services: { - searchSourceClient: searchSourceClientMock, + getSearchSourceClient: expect.any(Function), + getDataViews: expect.any(Function), logger, share: undefined, }, diff --git a/x-pack/plugins/stack_alerts/server/rule_types/es_query/executor.ts b/x-pack/plugins/stack_alerts/server/rule_types/es_query/executor.ts index f48c5d015e5de..2891139e03c36 100644 --- a/x-pack/plugins/stack_alerts/server/rule_types/es_query/executor.ts +++ b/x-pack/plugins/stack_alerts/server/rule_types/es_query/executor.ts @@ -54,8 +54,6 @@ export async function executor(core: CoreSetup, options: ExecutorOptions { // @ts-expect-error services: { logger, - searchSourceClient: searchSourceCommonMock, + getSearchSourceClient: async () => searchSourceCommonMock, }, spacePrefix: '', dateStart: new Date().toISOString(), @@ -467,7 +467,7 @@ describe('fetchSearchSourceQuery', () => { // @ts-expect-error services: { logger, - searchSourceClient: searchSourceCommonMock, + getSearchSourceClient: async () => searchSourceCommonMock, }, spacePrefix: '', dateStart: new Date().toISOString(), @@ -528,7 +528,7 @@ describe('fetchSearchSourceQuery', () => { const linkWithoutExcludedRuns = await generateLink( searchSourceInstance, locatorMock, - dataViews, + async () => dataViews, dataViewMock, dateStart, dateEnd, @@ -546,7 +546,7 @@ describe('fetchSearchSourceQuery', () => { const linkWithExcludedRuns = await generateLink( searchSourceInstance, locatorMock, - dataViews, + async () => dataViews, dataViewMock, dateStart, dateEnd, @@ -590,7 +590,7 @@ describe('fetchSearchSourceQuery', () => { await generateLink( searchSourceInstance, locatorMock, - dataViews, + async () => dataViews, dataViewMock, dateStart, dateEnd, diff --git a/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_search_source_query.ts b/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_search_source_query.ts index 20163ab065533..d88e23b5fb372 100644 --- a/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_search_source_query.ts +++ b/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_search_source_query.ts @@ -36,9 +36,9 @@ export interface FetchSearchSourceQueryOpts { spacePrefix: string; services: { logger: Logger; - searchSourceClient: ISearchStartSearchSource; + getSearchSourceClient: () => Promise; share: SharePluginStart; - dataViews: DataViewsContract; + getDataViews: () => Promise; }; dateStart: string; dateEnd: string; @@ -54,7 +54,8 @@ export async function fetchSearchSourceQuery({ dateStart, dateEnd, }: FetchSearchSourceQueryOpts) { - const { logger, searchSourceClient } = services; + const { logger, getSearchSourceClient } = services; + const searchSourceClient = await getSearchSourceClient(); const isGroupAgg = isGroupAggregation(params.termField); const isCountAgg = isCountAggregation(params.aggType); @@ -90,7 +91,7 @@ export async function fetchSearchSourceQuery({ const link = await generateLink( initialSearchSource, services.share.url.locators.get('DISCOVER_APP_LOCATOR')!, - services.dataViews, + services.getDataViews, index, dateStart, dateEnd, @@ -196,13 +197,14 @@ export async function updateSearchSource( export async function generateLink( searchSource: ISearchSource, discoverLocator: LocatorPublic, - dataViews: DataViewsContract, + getDataViews: () => Promise, dataViewToUpdate: DataView, dateStart: string, dateEnd: string, spacePrefix: string, filterToExcludeHitsFromPreviousRun: Filter | null ) { + const dataViews = await getDataViews(); const prevFilters = [...((searchSource.getField('filter') as Filter[]) || [])]; if (filterToExcludeHitsFromPreviousRun) { From 1aaee64008430ccce79b923a70ce8a7912a6aa52 Mon Sep 17 00:00:00 2001 From: Brad White Date: Wed, 4 Sep 2024 11:47:21 -0600 Subject: [PATCH 02/99] Update to latest caniuse-lite (#192051) This package logs out of date messages after 6 months. Updating to `latest`. Co-authored-by: Alex Szabo --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 84151aa6f23a9..cda35fbc6a9cd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13914,9 +13914,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001335, caniuse-lite@^1.0.30001587: - version "1.0.30001597" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz#8be94a8c1d679de23b22fbd944232aa1321639e6" - integrity sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w== + version "1.0.30001655" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz#0ce881f5a19a2dcfda2ecd927df4d5c1684b982f" + integrity sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg== canvg@^3.0.9: version "3.0.9" From 86a63dabef48beb3fc9ff12fb75b23c19bc2c5d8 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 4 Sep 2024 12:11:04 -0600 Subject: [PATCH 03/99] Revert "Integrate react control group embeddable into dashboard container (#190273) (#191993) #190273 introduced a performance regression. Reverting to move metrics to baseline again and create some time to identify root cause. Co-authored-by: Thomas Neirynck --- .../serialized_control_group_state.ts | 4 +- .../dashboard_with_controls_example.tsx | 12 +- .../control_group_persistence.ts | 28 ++ src/plugins/controls/common/index.ts | 2 + .../components/control_group.tsx | 1 - .../control_group_unsaved_changes_api.ts | 9 +- .../get_control_group_factory.tsx | 68 +--- .../init_controls_manager.test.ts | 192 ++++-------- .../control_group/init_controls_manager.ts | 72 ++--- .../open_edit_control_group_flyout.tsx | 2 +- .../control_group/serialization_utils.ts | 7 +- .../react_controls/control_group/types.ts | 3 +- .../initialize_data_control.test.tsx | 3 - .../data_controls/initialize_data_control.ts | 4 +- .../get_options_list_control_factory.tsx | 6 +- .../get_range_slider_control_factory.tsx | 5 +- .../data_controls/reference_name_utils.ts | 22 -- .../get_timeslider_control_factory.tsx | 10 +- .../controls/timeslider_control/types.ts | 6 +- .../dashboard_container_references.ts | 44 ++- .../dashboard_saved_object_references.ts | 18 ++ src/plugins/dashboard/common/types.ts | 3 + .../dashboard_app/locator/locator.test.ts | 10 +- .../add_data_control_button.tsx | 9 +- .../add_time_slider_control_button.tsx | 39 +-- .../controls_toolbar_button.tsx | 12 +- .../edit_control_group_button.tsx | 9 +- .../top_nav/dashboard_editing_toolbar.tsx | 8 +- .../top_nav/share/show_share_modal.tsx | 6 +- .../top_nav/use_dashboard_menu_items.tsx | 32 +- .../component/grid/dashboard_grid.test.tsx | 13 +- .../component/viewport/dashboard_viewport.tsx | 83 ++--- .../embeddable/api/run_save_functions.tsx | 35 ++- ...ashboard_control_group_integration.test.ts | 77 ++--- .../dashboard_control_group_integration.ts | 161 +++++----- .../create/create_dashboard.test.ts | 47 ++- .../embeddable/create/create_dashboard.ts | 163 +++++++++- .../data_views/sync_dashboard_data_views.ts | 26 +- .../embeddable/dashboard_container.test.tsx | 26 +- .../embeddable/dashboard_container.tsx | 135 ++------ .../diffing/dashboard_diffing_integration.ts | 26 +- .../public/dashboard_container/types.ts | 6 +- .../internal_dashboard_top_nav.tsx | 14 +- src/plugins/dashboard/public/mocks.tsx | 12 - .../dashboard_backup_service.ts | 2 - .../dashboard_content_management_service.ts | 9 +- .../lib/load_dashboard_state.ts | 5 +- .../lib/migrate_dashboard_input.test.ts | 25 +- .../lib/migrate_dashboard_input.ts | 22 ++ .../lib/save_dashboard_state.ts | 37 ++- .../dashboard_content_management/types.ts | 17 +- .../public/lib/containers/container.ts | 3 - .../public/lib/containers/i_container.ts | 2 - .../embeddable_compatibility_utils.ts | 6 +- .../lib/embeddables/diff_embeddable_input.ts | 3 - .../common/control_group_apply_button.ts | 87 +++++- .../controls/common/multiple_data_views.ts | 290 ++++++++---------- .../controls/common/replace_controls.ts | 16 +- .../options_list/options_list_suggestions.ts | 11 +- .../options_list/options_list_validation.ts | 42 ++- .../dashboard/current/kibana.json | 105 ------- .../current/multi_data_view_kibana.json | 64 ---- .../page_objects/dashboard_page_controls.ts | 10 +- .../app/metrics/static_dashboard/index.tsx | 10 +- 64 files changed, 1065 insertions(+), 1171 deletions(-) delete mode 100644 src/plugins/controls/public/react_controls/controls/data_controls/reference_name_utils.ts delete mode 100644 test/functional/fixtures/kbn_archiver/dashboard/current/multi_data_view_kibana.json diff --git a/examples/controls_example/public/app/react_control_example/serialized_control_group_state.ts b/examples/controls_example/public/app/react_control_example/serialized_control_group_state.ts index 9e4b18aaffa26..b02cf450cdd73 100644 --- a/examples/controls_example/public/app/react_control_example/serialized_control_group_state.ts +++ b/examples/controls_example/public/app/react_control_example/serialized_control_group_state.ts @@ -90,12 +90,12 @@ const initialSerializedControlGroupState = { } as object, references: [ { - name: `controlGroup_${rangeSliderControlId}:rangeSliderDataView`, + name: `controlGroup_${rangeSliderControlId}:${RANGE_SLIDER_CONTROL}DataView`, type: 'index-pattern', id: WEB_LOGS_DATA_VIEW_ID, }, { - name: `controlGroup_${optionsListId}:optionsListDataView`, + name: `controlGroup_${optionsListId}:${OPTIONS_LIST_CONTROL}DataView`, type: 'index-pattern', id: WEB_LOGS_DATA_VIEW_ID, }, diff --git a/examples/portable_dashboards_example/public/dashboard_with_controls_example.tsx b/examples/portable_dashboards_example/public/dashboard_with_controls_example.tsx index f63df505f5d85..ac902c72e851f 100644 --- a/examples/portable_dashboards_example/public/dashboard_with_controls_example.tsx +++ b/examples/portable_dashboards_example/public/dashboard_with_controls_example.tsx @@ -11,7 +11,8 @@ import React, { useEffect, useState } from 'react'; import { ViewMode } from '@kbn/embeddable-plugin/public'; import type { DataView } from '@kbn/data-views-plugin/public'; import { EuiPanel, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; -import { controlGroupStateBuilder } from '@kbn/controls-plugin/public'; +import { controlGroupInputBuilder } from '@kbn/controls-plugin/public'; +import { getDefaultControlGroupInput } from '@kbn/controls-plugin/common'; import { AwaitingDashboardAPI, DashboardRenderer, @@ -62,15 +63,16 @@ export const DashboardWithControlsExample = ({ dataView }: { dataView: DataView => { - const controlGroupState = {}; - await controlGroupStateBuilder.addDataControlFromField(controlGroupState, { + const builder = controlGroupInputBuilder; + const controlGroupInput = getDefaultControlGroupInput(); + await builder.addDataControlFromField(controlGroupInput, { dataViewId: dataView.id ?? '', title: 'Destintion country', fieldName: 'geo.dest', width: 'medium', grow: false, }); - await controlGroupStateBuilder.addDataControlFromField(controlGroupState, { + await builder.addDataControlFromField(controlGroupInput, { dataViewId: dataView.id ?? '', fieldName: 'bytes', width: 'medium', @@ -83,7 +85,7 @@ export const DashboardWithControlsExample = ({ dataView }: { dataView: DataView getInitialInput: () => ({ timeRange: { from: 'now-30d', to: 'now' }, viewMode: ViewMode.VIEW, - controlGroupState, + controlGroupInput, }), }; }} diff --git a/src/plugins/controls/common/control_group/control_group_persistence.ts b/src/plugins/controls/common/control_group/control_group_persistence.ts index 0de1238b9575c..8e9a795c2ec4c 100644 --- a/src/plugins/controls/common/control_group/control_group_persistence.ts +++ b/src/plugins/controls/common/control_group/control_group_persistence.ts @@ -9,6 +9,7 @@ import deepEqual from 'fast-deep-equal'; import { SerializableRecord } from '@kbn/utility-types'; +import { v4 } from 'uuid'; import { pick, omit, xor } from 'lodash'; import { @@ -22,6 +23,7 @@ import { } from './control_group_panel_diff_system'; import { ControlGroupInput } from '..'; import { + ControlsPanels, PersistableControlGroupInput, persistableControlGroupInputKeys, RawControlGroupAttributes, @@ -101,6 +103,32 @@ const getPanelsAreEqual = ( return true; }; +export const controlGroupInputToRawControlGroupAttributes = ( + controlGroupInput: Omit +): RawControlGroupAttributes => { + return { + controlStyle: controlGroupInput.controlStyle, + chainingSystem: controlGroupInput.chainingSystem, + showApplySelections: controlGroupInput.showApplySelections, + panelsJSON: JSON.stringify(controlGroupInput.panels), + ignoreParentSettingsJSON: JSON.stringify(controlGroupInput.ignoreParentSettings), + }; +}; + +export const generateNewControlIds = (controlGroupInput?: PersistableControlGroupInput) => { + if (!controlGroupInput?.panels) return; + + const newPanelsMap: ControlsPanels = {}; + for (const panel of Object.values(controlGroupInput.panels)) { + const newId = v4(); + newPanelsMap[newId] = { + ...panel, + explicitInput: { ...panel.explicitInput, id: newId }, + }; + } + return { ...controlGroupInput, panels: newPanelsMap }; +}; + export const rawControlGroupAttributesToControlGroupInput = ( rawControlGroupAttributes: RawControlGroupAttributes ): PersistableControlGroupInput | undefined => { diff --git a/src/plugins/controls/common/index.ts b/src/plugins/controls/common/index.ts index 6be0bc5818f57..69af581fc5fad 100644 --- a/src/plugins/controls/common/index.ts +++ b/src/plugins/controls/common/index.ts @@ -22,12 +22,14 @@ export { persistableControlGroupInputKeys, } from './control_group/types'; export { + controlGroupInputToRawControlGroupAttributes, rawControlGroupAttributesToControlGroupInput, rawControlGroupAttributesToSerializable, serializableToRawControlGroupAttributes, getDefaultControlGroupPersistableInput, persistableControlGroupInputIsEqual, getDefaultControlGroupInput, + generateNewControlIds, } from './control_group/control_group_persistence'; export { diff --git a/src/plugins/controls/public/react_controls/control_group/components/control_group.tsx b/src/plugins/controls/public/react_controls/control_group/components/control_group.tsx index 4a2a4c802272d..c825e9021b48d 100644 --- a/src/plugins/controls/public/react_controls/control_group/components/control_group.tsx +++ b/src/plugins/controls/public/react_controls/control_group/components/control_group.tsx @@ -121,7 +121,6 @@ export function ControlGroup({ paddingSize="none" color={draggingId ? 'success' : 'transparent'} className="controlsWrapper" - data-test-subj="controls-group-wrapper" > & { controlsInOrder: ControlsInOrder; }; @@ -34,7 +38,6 @@ export function initializeControlGroupUnsavedChanges( children$: PresentationContainer['children$'], comparators: StateComparators, snapshotControlsRuntimeState: () => ControlPanelsState, - resetControlsUnsavedChanges: () => void, parentApi: unknown, lastSavedRuntimeState: ControlGroupRuntimeState ) { @@ -44,6 +47,7 @@ export function initializeControlGroupUnsavedChanges( chainingSystem: lastSavedRuntimeState.chainingSystem, controlsInOrder: getControlsInOrder(lastSavedRuntimeState.initialChildControlState), ignoreParentSettings: lastSavedRuntimeState.ignoreParentSettings, + initialChildControlState: lastSavedRuntimeState.initialChildControlState, labelPosition: lastSavedRuntimeState.labelPosition, }, parentApi, @@ -68,7 +72,6 @@ export function initializeControlGroupUnsavedChanges( ), asyncResetUnsavedChanges: async () => { controlGroupUnsavedChanges.api.resetUnsavedChanges(); - resetControlsUnsavedChanges(); const filtersReadyPromises: Array> = []; Object.values(children$.value).forEach((controlApi) => { diff --git a/src/plugins/controls/public/react_controls/control_group/get_control_group_factory.tsx b/src/plugins/controls/public/react_controls/control_group/get_control_group_factory.tsx index 2e6519b69343f..45802689e81a1 100644 --- a/src/plugins/controls/public/react_controls/control_group/get_control_group_factory.tsx +++ b/src/plugins/controls/public/react_controls/control_group/get_control_group_factory.tsx @@ -34,19 +34,12 @@ import { chaining$, controlFetch$, controlGroupFetch$ } from './control_fetch'; import { initControlsManager } from './init_controls_manager'; import { openEditControlGroupFlyout } from './open_edit_control_group_flyout'; import { deserializeControlGroup } from './serialization_utils'; -import { - ControlGroupApi, - ControlGroupRuntimeState, - ControlGroupSerializedState, - ControlPanelsState, -} from './types'; +import { ControlGroupApi, ControlGroupRuntimeState, ControlGroupSerializedState } from './types'; import { ControlGroup } from './components/control_group'; import { initSelectionsManager } from './selections_manager'; import { initializeControlGroupUnsavedChanges } from './control_group_unsaved_changes_api'; import { openDataControlEditor } from '../controls/data_controls/open_data_control_editor'; -const DEFAULT_CHAINING_SYSTEM = 'HIERARCHICAL'; - export const getControlGroupEmbeddableFactory = (services: { core: CoreStart; dataViews: DataViewsPublicPluginStart; @@ -67,6 +60,7 @@ export const getControlGroupEmbeddableFactory = (services: { lastSavedRuntimeState ) => { const { + initialChildControlState, labelPosition: initialLabelPosition, chainingSystem, autoApplySelections, @@ -74,22 +68,19 @@ export const getControlGroupEmbeddableFactory = (services: { } = initialRuntimeState; const autoApplySelections$ = new BehaviorSubject(autoApplySelections); - const defaultDataViewId = await services.dataViews.getDefaultId(); - const lastSavedControlsState$ = new BehaviorSubject( - lastSavedRuntimeState.initialChildControlState - ); + const parentDataViewId = apiPublishesDataViews(parentApi) + ? parentApi.dataViews.value?.[0]?.id + : undefined; const controlsManager = initControlsManager( - initialRuntimeState.initialChildControlState, - lastSavedControlsState$ + initialChildControlState, + parentDataViewId ?? (await services.dataViews.getDefaultId()) ); const selectionsManager = initSelectionsManager({ ...controlsManager.api, autoApplySelections$, }); const dataViews = new BehaviorSubject(undefined); - const chainingSystem$ = new BehaviorSubject( - chainingSystem ?? DEFAULT_CHAINING_SYSTEM - ); + const chainingSystem$ = new BehaviorSubject(chainingSystem); const ignoreParentSettings$ = new BehaviorSubject( ignoreParentSettings ); @@ -113,7 +104,6 @@ export const getControlGroupEmbeddableFactory = (services: { chainingSystem: [ chainingSystem$, (next: ControlGroupChainingSystem) => chainingSystem$.next(next), - (a, b) => (a ?? DEFAULT_CHAINING_SYSTEM) === (b ?? DEFAULT_CHAINING_SYSTEM), ], ignoreParentSettings: [ ignoreParentSettings$, @@ -123,7 +113,6 @@ export const getControlGroupEmbeddableFactory = (services: { labelPosition: [labelPosition$, (next: ControlStyle) => labelPosition$.next(next)], }, controlsManager.snapshotControlsRuntimeState, - controlsManager.resetControlsUnsavedChanges, parentApi, lastSavedRuntimeState ); @@ -170,28 +159,20 @@ export const getControlGroupEmbeddableFactory = (services: { i18n.translate('controls.controlGroup.displayName', { defaultMessage: 'Controls', }), - openAddDataControlFlyout: (options) => { - const parentDataViewId = apiPublishesDataViews(parentApi) - ? parentApi.dataViews.value?.[0]?.id - : undefined; - const newControlState = controlsManager.getNewControlState(); + openAddDataControlFlyout: (settings) => { + const { controlInputTransform } = settings ?? { + controlInputTransform: (state) => state, + }; openDataControlEditor({ - initialState: { - ...newControlState, - dataViewId: - newControlState.dataViewId ?? parentDataViewId ?? defaultDataViewId ?? undefined, - }, + initialState: controlsManager.getNewControlState(), onSave: ({ type: controlType, state: initialState }) => { controlsManager.api.addNewPanel({ panelType: controlType, - initialState: options?.controlInputTransform - ? options.controlInputTransform( - initialState as Partial, - controlType - ) - : initialState, + initialState: controlInputTransform!( + initialState as Partial, + controlType + ), }); - options?.onSave?.(); }, controlGroupApi: api, services, @@ -226,20 +207,6 @@ export const getControlGroupEmbeddableFactory = (services: { dataViews.next(newDataViews) ); - const saveNotificationSubscription = apiHasSaveNotification(parentApi) - ? parentApi.saveNotification$.subscribe(() => { - lastSavedControlsState$.next(controlsManager.snapshotControlsRuntimeState()); - - if ( - typeof autoApplySelections$.value === 'boolean' && - !autoApplySelections$.value && - selectionsManager.hasUnappliedSelections$.value - ) { - selectionsManager.applySelections(); - } - }) - : undefined; - /** Fetch the allowExpensiveQuries setting for the children to use if necessary */ try { const { allowExpensiveQueries } = await services.core.http.get<{ @@ -268,7 +235,6 @@ export const getControlGroupEmbeddableFactory = (services: { return () => { selectionsManager.cleanup(); childrenDataViewsSubscription.unsubscribe(); - saveNotificationSubscription?.unsubscribe(); }; }, []); diff --git a/src/plugins/controls/public/react_controls/control_group/init_controls_manager.test.ts b/src/plugins/controls/public/react_controls/control_group/init_controls_manager.test.ts index fc729478ec770..3e381123ecd9a 100644 --- a/src/plugins/controls/public/react_controls/control_group/init_controls_manager.test.ts +++ b/src/plugins/controls/public/react_controls/control_group/init_controls_manager.test.ts @@ -6,26 +6,27 @@ * Side Public License, v 1. */ -import { BehaviorSubject } from 'rxjs'; import { DefaultDataControlState } from '../controls/data_controls/types'; import { DefaultControlApi } from '../controls/types'; import { initControlsManager, getLastUsedDataViewId } from './init_controls_manager'; -import { ControlPanelState, ControlPanelsState } from './types'; +import { ControlPanelState } from './types'; jest.mock('uuid', () => ({ v4: jest.fn().mockReturnValue('delta'), })); -describe('PresentationContainer api', () => { - const intialControlsState = { - alpha: { type: 'testControl', order: 0 }, - bravo: { type: 'testControl', order: 1 }, - charlie: { type: 'testControl', order: 2 }, - }; - const lastSavedControlsState$ = new BehaviorSubject(intialControlsState); +const DEFAULT_DATA_VIEW_ID = 'myDataView'; +describe('PresentationContainer api', () => { test('addNewPanel should add control at end of controls', async () => { - const controlsManager = initControlsManager(intialControlsState, lastSavedControlsState$); + const controlsManager = initControlsManager( + { + alpha: { type: 'testControl', order: 0 }, + bravo: { type: 'testControl', order: 1 }, + charlie: { type: 'testControl', order: 2 }, + }, + DEFAULT_DATA_VIEW_ID + ); const addNewPanelPromise = controlsManager.api.addNewPanel({ panelType: 'testControl', initialState: {}, @@ -41,7 +42,14 @@ describe('PresentationContainer api', () => { }); test('removePanel should remove control', () => { - const controlsManager = initControlsManager(intialControlsState, lastSavedControlsState$); + const controlsManager = initControlsManager( + { + alpha: { type: 'testControl', order: 0 }, + bravo: { type: 'testControl', order: 1 }, + charlie: { type: 'testControl', order: 2 }, + }, + DEFAULT_DATA_VIEW_ID + ); controlsManager.api.removePanel('bravo'); expect(controlsManager.controlsInOrder$.value.map((element) => element.id)).toEqual([ 'alpha', @@ -50,7 +58,14 @@ describe('PresentationContainer api', () => { }); test('replacePanel should replace control', async () => { - const controlsManager = initControlsManager(intialControlsState, lastSavedControlsState$); + const controlsManager = initControlsManager( + { + alpha: { type: 'testControl', order: 0 }, + bravo: { type: 'testControl', order: 1 }, + charlie: { type: 'testControl', order: 2 }, + }, + DEFAULT_DATA_VIEW_ID + ); const replacePanelPromise = controlsManager.api.replacePanel('bravo', { panelType: 'testControl', initialState: {}, @@ -66,7 +81,13 @@ describe('PresentationContainer api', () => { describe('untilInitialized', () => { test('should not resolve until all controls are initialized', async () => { - const controlsManager = initControlsManager(intialControlsState, lastSavedControlsState$); + const controlsManager = initControlsManager( + { + alpha: { type: 'testControl', order: 0 }, + bravo: { type: 'testControl', order: 1 }, + }, + DEFAULT_DATA_VIEW_ID + ); let isDone = false; controlsManager.api.untilInitialized().then(() => { isDone = true; @@ -80,18 +101,19 @@ describe('PresentationContainer api', () => { controlsManager.setControlApi('bravo', {} as unknown as DefaultControlApi); await new Promise((resolve) => setTimeout(resolve, 0)); - expect(isDone).toBe(false); - - controlsManager.setControlApi('charlie', {} as unknown as DefaultControlApi); - await new Promise((resolve) => setTimeout(resolve, 0)); expect(isDone).toBe(true); }); test('should resolve when all control already initialized ', async () => { - const controlsManager = initControlsManager(intialControlsState, lastSavedControlsState$); + const controlsManager = initControlsManager( + { + alpha: { type: 'testControl', order: 0 }, + bravo: { type: 'testControl', order: 1 }, + }, + DEFAULT_DATA_VIEW_ID + ); controlsManager.setControlApi('alpha', {} as unknown as DefaultControlApi); controlsManager.setControlApi('bravo', {} as unknown as DefaultControlApi); - controlsManager.setControlApi('charlie', {} as unknown as DefaultControlApi); let isDone = false; controlsManager.api.untilInitialized().then(() => { @@ -105,14 +127,14 @@ describe('PresentationContainer api', () => { }); describe('snapshotControlsRuntimeState', () => { - const intialControlsState = { - alpha: { type: 'testControl', order: 1 }, - bravo: { type: 'testControl', order: 0 }, - }; - const lastSavedControlsState$ = new BehaviorSubject(intialControlsState); - test('should snapshot runtime state for all controls', async () => { - const controlsManager = initControlsManager(intialControlsState, lastSavedControlsState$); + const controlsManager = initControlsManager( + { + alpha: { type: 'testControl', order: 1 }, + bravo: { type: 'testControl', order: 0 }, + }, + DEFAULT_DATA_VIEW_ID + ); controlsManager.setControlApi('alpha', { snapshotRuntimeState: () => { return { key1: 'alpha value' }; @@ -168,120 +190,28 @@ describe('getLastUsedDataViewId', () => { }); }); -describe('resetControlsUnsavedChanges', () => { - test(`should remove previous sessions's unsaved changes on reset`, () => { - // last session's unsaved changes added 1 control - const intialControlsState = { - alpha: { type: 'testControl', order: 0 }, - }; - // last saved state is empty control group - const lastSavedControlsState$ = new BehaviorSubject({}); - const controlsManager = initControlsManager(intialControlsState, lastSavedControlsState$); - controlsManager.setControlApi('alpha', {} as unknown as DefaultControlApi); - - expect(controlsManager.controlsInOrder$.value).toEqual([ - { - id: 'alpha', - type: 'testControl', - }, - ]); - - controlsManager.resetControlsUnsavedChanges(); - expect(controlsManager.controlsInOrder$.value).toEqual([]); - }); - - test('should restore deleted control on reset', () => { - const intialControlsState = { - alpha: { type: 'testControl', order: 0 }, - }; - const lastSavedControlsState$ = new BehaviorSubject(intialControlsState); - const controlsManager = initControlsManager(intialControlsState, lastSavedControlsState$); - controlsManager.setControlApi('alpha', {} as unknown as DefaultControlApi); - - // delete control - controlsManager.api.removePanel('alpha'); - - // deleted control should exist on reset - controlsManager.resetControlsUnsavedChanges(); - expect(controlsManager.controlsInOrder$.value).toEqual([ - { - id: 'alpha', - type: 'testControl', - }, - ]); - }); - - test('should restore controls to last saved state', () => { - const intialControlsState = {}; - const lastSavedControlsState$ = new BehaviorSubject(intialControlsState); - const controlsManager = initControlsManager(intialControlsState, lastSavedControlsState$); - - // add control - controlsManager.api.addNewPanel({ panelType: 'testControl' }); - controlsManager.setControlApi('delta', { - snapshotRuntimeState: () => { - return {}; - }, - } as unknown as DefaultControlApi); - - // simulate save - lastSavedControlsState$.next(controlsManager.snapshotControlsRuntimeState()); - - // saved control should exist on reset - controlsManager.resetControlsUnsavedChanges(); - expect(controlsManager.controlsInOrder$.value).toEqual([ - { - id: 'delta', - type: 'testControl', - }, - ]); - }); - - // Test edge case where adding a panel and resetting left orphaned control in children$ - test('should remove orphaned children on reset', () => { - // baseline last saved state contains a single control - const intialControlsState = { - alpha: { type: 'testControl', order: 0 }, - }; - const lastSavedControlsState$ = new BehaviorSubject(intialControlsState); - const controlsManager = initControlsManager(intialControlsState, lastSavedControlsState$); - controlsManager.setControlApi('alpha', {} as unknown as DefaultControlApi); - - // add another control - controlsManager.api.addNewPanel({ panelType: 'testControl' }); - controlsManager.setControlApi('delta', {} as unknown as DefaultControlApi); - expect(Object.keys(controlsManager.api.children$.value).length).toBe(2); - - // reset to lastSavedControlsState - controlsManager.resetControlsUnsavedChanges(); - // children$ should no longer contain control removed by resetting back to original control baseline - expect(Object.keys(controlsManager.api.children$.value).length).toBe(1); - }); -}); - describe('getNewControlState', () => { test('should contain defaults when there are no existing controls', () => { - const controlsManager = initControlsManager({}, new BehaviorSubject({})); + const controlsManager = initControlsManager({}, DEFAULT_DATA_VIEW_ID); expect(controlsManager.getNewControlState()).toEqual({ grow: true, width: 'medium', - dataViewId: undefined, + dataViewId: DEFAULT_DATA_VIEW_ID, }); }); test('should start with defaults if there are existing controls', () => { - const intialControlsState = { - alpha: { - type: 'testControl', - order: 1, - dataViewId: 'myOtherDataViewId', - width: 'small', - grow: false, - } as ControlPanelState & Pick, - }; const controlsManager = initControlsManager( - intialControlsState, - new BehaviorSubject(intialControlsState) + { + alpha: { + type: 'testControl', + order: 1, + dataViewId: 'myOtherDataViewId', + width: 'small', + grow: false, + } as ControlPanelState & Pick, + }, + DEFAULT_DATA_VIEW_ID ); expect(controlsManager.getNewControlState()).toEqual({ grow: true, @@ -291,7 +221,7 @@ describe('getNewControlState', () => { }); test('should contain values of last added control', () => { - const controlsManager = initControlsManager({}, new BehaviorSubject({})); + const controlsManager = initControlsManager({}, DEFAULT_DATA_VIEW_ID); controlsManager.api.addNewPanel({ panelType: 'testControl', initialState: { diff --git a/src/plugins/controls/public/react_controls/control_group/init_controls_manager.ts b/src/plugins/controls/public/react_controls/control_group/init_controls_manager.ts index aaa5d41e492ae..07b533f329631 100644 --- a/src/plugins/controls/public/react_controls/control_group/init_controls_manager.ts +++ b/src/plugins/controls/public/react_controls/control_group/init_controls_manager.ts @@ -38,25 +38,22 @@ export function getControlsInOrder(initialControlPanelsState: ControlPanelsState } export function initControlsManager( - /** - * Composed from last saved controls state and previous sessions's unsaved changes to controls state - */ - initialControlsState: ControlPanelsState, - /** - * Observable that publishes last saved controls state only - */ - lastSavedControlsState$: PublishingSubject + initialControlPanelsState: ControlPanelsState, + defaultDataViewId: string | null ) { - const initialControlIds = Object.keys(initialControlsState); + const lastSavedControlsPanelState$ = new BehaviorSubject(initialControlPanelsState); + const initialControlIds = Object.keys(initialControlPanelsState); const children$ = new BehaviorSubject<{ [key: string]: DefaultControlApi }>({}); - let currentControlsState: { [panelId: string]: DefaultControlState } = { - ...initialControlsState, + let controlsPanelState: { [panelId: string]: DefaultControlState } = { + ...initialControlPanelsState, }; const controlsInOrder$ = new BehaviorSubject( - getControlsInOrder(initialControlsState) + getControlsInOrder(initialControlPanelsState) ); const lastUsedDataViewId$ = new BehaviorSubject( - getLastUsedDataViewId(controlsInOrder$.value, initialControlsState) + getLastUsedDataViewId(controlsInOrder$.value, initialControlPanelsState) ?? + defaultDataViewId ?? + undefined ); const lastUsedWidth$ = new BehaviorSubject(DEFAULT_CONTROL_WIDTH); const lastUsedGrow$ = new BehaviorSubject(DEFAULT_CONTROL_GROW); @@ -111,12 +108,12 @@ export function initControlsManager( type: panelType, }); controlsInOrder$.next(nextControlsInOrder); - currentControlsState[id] = initialState ?? {}; + controlsPanelState[id] = initialState ?? {}; return await untilControlLoaded(id); } function removePanel(panelId: string) { - delete currentControlsState[panelId]; + delete controlsPanelState[panelId]; controlsInOrder$.next(controlsInOrder$.value.filter(({ id }) => id !== panelId)); children$.next(omit(children$.value, panelId)); } @@ -164,7 +161,7 @@ export function initControlsManager( type: controlApi.type, width, /** Re-add the `explicitInput` layer on serialize so control group saved object retains shape */ - explicitInput: { id, ...rest }, + explicitInput: rest, }; }); @@ -187,30 +184,9 @@ export function initControlsManager( }); return controlsRuntimeState; }, - resetControlsUnsavedChanges: () => { - currentControlsState = { - ...lastSavedControlsState$.value, - }; - const nextControlsInOrder = getControlsInOrder(currentControlsState as ControlPanelsState); - controlsInOrder$.next(nextControlsInOrder); - - const nextControlIds = nextControlsInOrder.map(({ id }) => id); - const children = { ...children$.value }; - let modifiedChildren = false; - Object.keys(children).forEach((controlId) => { - if (!nextControlIds.includes(controlId)) { - // remove children that no longer exist after reset - delete children[controlId]; - modifiedChildren = true; - } - }); - if (modifiedChildren) { - children$.next(children); - } - }, api: { getSerializedStateForChild: (childId: string) => { - const controlPanelState = currentControlsState[childId]; + const controlPanelState = controlsPanelState[childId]; return controlPanelState ? { rawState: controlPanelState } : undefined; }, children$: children$ as PublishingSubject<{ @@ -254,10 +230,26 @@ export function initControlsManager( comparators: { controlsInOrder: [ controlsInOrder$, - (next: ControlsInOrder) => {}, // setter does nothing, controlsInOrder$ reset by resetControlsRuntimeState + (next: ControlsInOrder) => controlsInOrder$.next(next), fastIsEqual, ], - } as StateComparators>, + // Control state differences tracked by controlApi comparators + // Control ordering differences tracked by controlsInOrder comparator + // initialChildControlState comparatator exists to reset controls manager to last saved state + initialChildControlState: [ + lastSavedControlsPanelState$, + (lastSavedControlPanelsState: ControlPanelsState) => { + lastSavedControlsPanelState$.next(lastSavedControlPanelsState); + controlsPanelState = { + ...lastSavedControlPanelsState, + }; + controlsInOrder$.next(getControlsInOrder(lastSavedControlPanelsState)); + }, + () => true, + ], + } as StateComparators< + Pick + >, }; } diff --git a/src/plugins/controls/public/react_controls/control_group/open_edit_control_group_flyout.tsx b/src/plugins/controls/public/react_controls/control_group/open_edit_control_group_flyout.tsx index 98784f826090b..c636d37ade6b2 100644 --- a/src/plugins/controls/public/react_controls/control_group/open_edit_control_group_flyout.tsx +++ b/src/plugins/controls/public/react_controls/control_group/open_edit_control_group_flyout.tsx @@ -72,7 +72,7 @@ export const openEditControlGroupFlyout = ( Object.keys(controlGroupApi.children$.getValue()).forEach((childId) => { controlGroupApi.removePanel(childId); }); - closeOverlay(ref); + ref.close(); }); }; diff --git a/src/plugins/controls/public/react_controls/control_group/serialization_utils.ts b/src/plugins/controls/public/react_controls/control_group/serialization_utils.ts index 031dababa5ca1..eb3706c3913a1 100644 --- a/src/plugins/controls/public/react_controls/control_group/serialization_utils.ts +++ b/src/plugins/controls/public/react_controls/control_group/serialization_utils.ts @@ -9,7 +9,6 @@ import { SerializedPanelState } from '@kbn/presentation-containers'; import { omit } from 'lodash'; import { ControlGroupRuntimeState, ControlGroupSerializedState } from './types'; -import { parseReferenceName } from '../controls/data_controls/reference_name_utils'; export const deserializeControlGroup = ( state: SerializedPanelState @@ -21,9 +20,9 @@ export const deserializeControlGroup = ( const references = state.references ?? []; references.forEach((reference) => { const referenceName = reference.name; - const { controlId } = parseReferenceName(referenceName); - if (panels[controlId]) { - panels[controlId].dataViewId = reference.id; + const panelId = referenceName.substring('controlGroup_'.length, referenceName.lastIndexOf(':')); + if (panels[panelId]) { + panels[panelId].dataViewId = reference.id; } }); diff --git a/src/plugins/controls/public/react_controls/control_group/types.ts b/src/plugins/controls/public/react_controls/control_group/types.ts index 826a5fde393b1..d009712e52a5b 100644 --- a/src/plugins/controls/public/react_controls/control_group/types.ts +++ b/src/plugins/controls/public/react_controls/control_group/types.ts @@ -65,9 +65,8 @@ export type ControlGroupApi = PresentationContainer & ignoreParentSettings$: PublishingSubject; allowExpensiveQueries$: PublishingSubject; untilInitialized: () => Promise; - openAddDataControlFlyout: (options?: { + openAddDataControlFlyout: (settings?: { controlInputTransform?: ControlInputTransform; - onSave?: () => void; }) => void; labelPosition: PublishingSubject; }; diff --git a/src/plugins/controls/public/react_controls/controls/data_controls/initialize_data_control.test.tsx b/src/plugins/controls/public/react_controls/controls/data_controls/initialize_data_control.test.tsx index 5baca7edfdaab..5dd6bf745feca 100644 --- a/src/plugins/controls/public/react_controls/controls/data_controls/initialize_data_control.test.tsx +++ b/src/plugins/controls/public/react_controls/controls/data_controls/initialize_data_control.test.tsx @@ -51,7 +51,6 @@ describe('initializeDataControl', () => { dataControl = initializeDataControl( 'myControlId', 'myControlType', - 'referenceNameSuffix', dataControlState, editorStateManager, controlGroupApi, @@ -83,7 +82,6 @@ describe('initializeDataControl', () => { dataControl = initializeDataControl( 'myControlId', 'myControlType', - 'referenceNameSuffix', { ...dataControlState, dataViewId: 'notGonnaFindMeDataViewId', @@ -122,7 +120,6 @@ describe('initializeDataControl', () => { dataControl = initializeDataControl( 'myControlId', 'myControlType', - 'referenceNameSuffix', { ...dataControlState, fieldName: 'notGonnaFindMeFieldName', diff --git a/src/plugins/controls/public/react_controls/controls/data_controls/initialize_data_control.ts b/src/plugins/controls/public/react_controls/controls/data_controls/initialize_data_control.ts index d3b90e72bb7fa..312701dd22c32 100644 --- a/src/plugins/controls/public/react_controls/controls/data_controls/initialize_data_control.ts +++ b/src/plugins/controls/public/react_controls/controls/data_controls/initialize_data_control.ts @@ -26,12 +26,10 @@ import { initializeDefaultControlApi } from '../initialize_default_control_api'; import { ControlApiInitialization, ControlStateManager, DefaultControlState } from '../types'; import { openDataControlEditor } from './open_data_control_editor'; import { DataControlApi, DataControlFieldFormatter, DefaultDataControlState } from './types'; -import { getReferenceName } from './reference_name_utils'; export const initializeDataControl = ( controlId: string, controlType: string, - referenceNameSuffix: string, state: DefaultDataControlState, /** * `This state manager` should only include the state that the data control editor is @@ -244,7 +242,7 @@ export const initializeDataControl = ( }, references: [ { - name: getReferenceName(controlId, referenceNameSuffix), + name: `controlGroup_${controlId}:${controlType}DataView`, type: DATA_VIEW_SAVED_OBJECT_TYPE, id: dataViewId.getValue(), }, diff --git a/src/plugins/controls/public/react_controls/controls/data_controls/options_list_control/get_options_list_control_factory.tsx b/src/plugins/controls/public/react_controls/controls/data_controls/options_list_control/get_options_list_control_factory.tsx index 4a16fcfe29b31..12d0de5a3d7d3 100644 --- a/src/plugins/controls/public/react_controls/controls/data_controls/options_list_control/get_options_list_control_factory.tsx +++ b/src/plugins/controls/public/react_controls/controls/data_controls/options_list_control/get_options_list_control_factory.tsx @@ -8,7 +8,6 @@ import React, { useEffect } from 'react'; import { BehaviorSubject, combineLatest, debounceTime, filter, skip } from 'rxjs'; -import fastIsEqual from 'fast-deep-equal'; import { buildExistsFilter, buildPhraseFilter, buildPhrasesFilter, Filter } from '@kbn/es-query'; import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing'; @@ -88,7 +87,6 @@ export const getOptionsListControlFactory = ( >( uuid, OPTIONS_LIST_CONTROL, - 'optionsListDataView', initialState, { searchTechnique: searchTechnique$, singleSelect: singleSelect$ }, controlGroupApi, @@ -245,7 +243,7 @@ export const getOptionsListControlFactory = ( searchTechnique: searchTechnique$.getValue(), runPastTimeout: runPastTimeout$.getValue(), singleSelect: singleSelect$.getValue(), - selectedOptions: selections.selectedOptions$.getValue(), + selections: selections.selectedOptions$.getValue(), sort: sort$.getValue(), existsSelected: selections.existsSelected$.getValue(), exclude: selections.exclude$.getValue(), @@ -279,7 +277,7 @@ export const getOptionsListControlFactory = ( sort: [ sort$, (sort) => sort$.next(sort), - (a, b) => fastIsEqual(a ?? OPTIONS_LIST_DEFAULT_SORT, b ?? OPTIONS_LIST_DEFAULT_SORT), + (a, b) => (a ?? OPTIONS_LIST_DEFAULT_SORT) === (b ?? OPTIONS_LIST_DEFAULT_SORT), ], /** This state cannot currently be changed after the control is created */ diff --git a/src/plugins/controls/public/react_controls/controls/data_controls/range_slider/get_range_slider_control_factory.tsx b/src/plugins/controls/public/react_controls/controls/data_controls/range_slider/get_range_slider_control_factory.tsx index 88f0497ac5cba..a2819460d05c9 100644 --- a/src/plugins/controls/public/react_controls/controls/data_controls/range_slider/get_range_slider_control_factory.tsx +++ b/src/plugins/controls/public/react_controls/controls/data_controls/range_slider/get_range_slider_control_factory.tsx @@ -63,7 +63,6 @@ export const getRangesliderControlFactory = ( const dataControl = initializeDataControl>( uuid, RANGE_SLIDER_CONTROL, - 'rangeSliderDataView', initialState, { step: step$, @@ -159,8 +158,8 @@ export const getRangesliderControlFactory = ( if (error) { dataControl.api.setBlockingError(error); } - max$.next(max !== undefined ? Math.ceil(max) : undefined); - min$.next(min !== undefined ? Math.floor(min) : undefined); + max$.next(max); + min$.next(min); } ); diff --git a/src/plugins/controls/public/react_controls/controls/data_controls/reference_name_utils.ts b/src/plugins/controls/public/react_controls/controls/data_controls/reference_name_utils.ts deleted file mode 100644 index 1a8a1e65f72de..0000000000000 --- a/src/plugins/controls/public/react_controls/controls/data_controls/reference_name_utils.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 REFERENCE_NAME_PREFIX = 'controlGroup_'; - -export function getReferenceName(controlId: string, referenceNameSuffix: string) { - return `${REFERENCE_NAME_PREFIX}${controlId}:${referenceNameSuffix}`; -} - -export function parseReferenceName(referenceName: string) { - return { - controlId: referenceName.substring( - REFERENCE_NAME_PREFIX.length, - referenceName.lastIndexOf(':') - ), - }; -} diff --git a/src/plugins/controls/public/react_controls/controls/timeslider_control/get_timeslider_control_factory.tsx b/src/plugins/controls/public/react_controls/controls/timeslider_control/get_timeslider_control_factory.tsx index ef8ea463a9f63..f3d1b43de8fa2 100644 --- a/src/plugins/controls/public/react_controls/controls/timeslider_control/get_timeslider_control_factory.tsx +++ b/src/plugins/controls/public/react_controls/controls/timeslider_control/get_timeslider_control_factory.tsx @@ -35,17 +35,16 @@ import './components/index.scss'; import { TimeSliderPrepend } from './components/time_slider_prepend'; import { TIME_SLIDER_CONTROL } from '../../../../common'; -const displayName = i18n.translate('controls.timesliderControl.displayName', { - defaultMessage: 'Time slider', -}); - export const getTimesliderControlFactory = ( services: Services ): ControlFactory => { return { type: TIME_SLIDER_CONTROL, getIconType: () => 'search', - getDisplayName: () => displayName, + getDisplayName: () => + i18n.translate('controls.timesliderControl.displayName', { + defaultMessage: 'Time slider', + }), buildControl: async (initialState, buildApi, uuid, controlGroupApi) => { const { timeRangeMeta$, formatDate, cleanupTimeRangeSubscription } = initTimeRangeSubscription(controlGroupApi, services); @@ -204,7 +203,6 @@ export const getTimesliderControlFactory = ( const api = buildApi( { ...defaultControl.api, - defaultPanelTitle: new BehaviorSubject(displayName), timeslice$, serializeState: () => { const { rawState: defaultControlState } = defaultControl.serialize(); diff --git a/src/plugins/controls/public/react_controls/controls/timeslider_control/types.ts b/src/plugins/controls/public/react_controls/controls/timeslider_control/types.ts index d7c837732cce4..bc5fcd67829c2 100644 --- a/src/plugins/controls/public/react_controls/controls/timeslider_control/types.ts +++ b/src/plugins/controls/public/react_controls/controls/timeslider_control/types.ts @@ -8,7 +8,7 @@ import { CoreStart } from '@kbn/core/public'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; -import type { PublishesPanelTitle, PublishesTimeslice } from '@kbn/presentation-publishing'; +import type { PublishesTimeslice } from '@kbn/presentation-publishing'; import type { DefaultControlApi, DefaultControlState } from '../types'; export type Timeslice = [number, number]; @@ -20,9 +20,7 @@ export interface TimesliderControlState extends DefaultControlState { timesliceEndAsPercentageOfTimeRange?: number; } -export type TimesliderControlApi = DefaultControlApi & - Pick & - PublishesTimeslice; +export type TimesliderControlApi = DefaultControlApi & PublishesTimeslice; export interface Services { core: CoreStart; diff --git a/src/plugins/dashboard/common/dashboard_container/persistable_state/dashboard_container_references.ts b/src/plugins/dashboard/common/dashboard_container/persistable_state/dashboard_container_references.ts index 169af0ca27da4..f1f6efb0d6678 100644 --- a/src/plugins/dashboard/common/dashboard_container/persistable_state/dashboard_container_references.ts +++ b/src/plugins/dashboard/common/dashboard_container/persistable_state/dashboard_container_references.ts @@ -7,6 +7,7 @@ */ import type { Reference } from '@kbn/content-management-utils'; +import { CONTROL_GROUP_TYPE, PersistableControlGroupInput } from '@kbn/controls-plugin/common'; import { EmbeddableInput, EmbeddablePersistableStateService, @@ -22,10 +23,6 @@ export const getReferencesForPanelId = (id: string, references: Reference[]): Re return filteredReferences; }; -export const getReferencesForControls = (references: Reference[]): Reference[] => { - return references.filter((reference) => reference.name.startsWith(controlGroupReferencePrefix)); -}; - export const prefixReferencesFromPanel = (id: string, references: Reference[]): Reference[] => { const prefix = `${id}:`; return references @@ -37,6 +34,7 @@ export const prefixReferencesFromPanel = (id: string, references: Reference[]): }; const controlGroupReferencePrefix = 'controlGroup_'; +const controlGroupId = 'dashboard_control_group'; export const createInject = ( persistableStateService: EmbeddablePersistableStateService @@ -92,6 +90,27 @@ export const createInject = ( } } + // since the controlGroup is not part of the panels array, its references need to be injected separately + if ('controlGroupInput' in workingState && workingState.controlGroupInput) { + const controlGroupReferences = references + .filter((reference) => reference.name.indexOf(controlGroupReferencePrefix) === 0) + .map((reference) => ({ + ...reference, + name: reference.name.replace(controlGroupReferencePrefix, ''), + })); + + const { type, ...injectedControlGroupState } = persistableStateService.inject( + { + ...workingState.controlGroupInput, + type: CONTROL_GROUP_TYPE, + id: controlGroupId, + }, + controlGroupReferences + ); + workingState.controlGroupInput = + injectedControlGroupState as unknown as PersistableControlGroupInput; + } + return workingState as EmbeddableStateWithType; }; }; @@ -141,6 +160,23 @@ export const createExtract = ( } } + // since the controlGroup is not part of the panels array, its references need to be extracted separately + if ('controlGroupInput' in workingState && workingState.controlGroupInput) { + const { state: extractedControlGroupState, references: controlGroupReferences } = + persistableStateService.extract({ + ...workingState.controlGroupInput, + type: CONTROL_GROUP_TYPE, + id: controlGroupId, + }); + workingState.controlGroupInput = + extractedControlGroupState as unknown as PersistableControlGroupInput; + const prefixedControlGroupReferences = controlGroupReferences.map((reference) => ({ + ...reference, + name: `${controlGroupReferencePrefix}${reference.name}`, + })); + references.push(...prefixedControlGroupReferences); + } + return { state: workingState as EmbeddableStateWithType, references }; }; }; diff --git a/src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.ts b/src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.ts index d6a852807bea3..94e8582ebecae 100644 --- a/src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.ts +++ b/src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.ts @@ -8,6 +8,7 @@ import type { Reference } from '@kbn/content-management-utils'; import { EmbeddablePersistableStateService } from '@kbn/embeddable-plugin/common/types'; +import { rawControlGroupAttributesToControlGroupInput } from '@kbn/controls-plugin/common'; import { convertPanelMapToSavedPanels, @@ -32,6 +33,9 @@ function parseDashboardAttributesWithType( } return { + controlGroupInput: + attributes.controlGroupInput && + rawControlGroupAttributesToControlGroupInput(attributes.controlGroupInput), type: 'dashboard', panels: convertSavedPanelsToPanelMap(parsedPanels), } as ParsedDashboardAttributesWithType; @@ -55,6 +59,13 @@ export function injectReferences( panelsJSON: JSON.stringify(injectedPanels), } as DashboardAttributes; + if (attributes.controlGroupInput && injectedState.controlGroupInput) { + newAttributes.controlGroupInput = { + ...attributes.controlGroupInput, + panelsJSON: JSON.stringify(injectedState.controlGroupInput.panels), + }; + } + return newAttributes; } @@ -85,6 +96,13 @@ export function extractReferences( panelsJSON: JSON.stringify(extractedPanels), } as DashboardAttributes; + if (attributes.controlGroupInput && extractedState.controlGroupInput) { + newAttributes.controlGroupInput = { + ...attributes.controlGroupInput, + panelsJSON: JSON.stringify(extractedState.controlGroupInput.panels), + }; + } + return { references: [...references, ...extractedReferences], attributes: newAttributes, diff --git a/src/plugins/dashboard/common/types.ts b/src/plugins/dashboard/common/types.ts index fd434085b397b..b5492d62ea220 100644 --- a/src/plugins/dashboard/common/types.ts +++ b/src/plugins/dashboard/common/types.ts @@ -8,6 +8,8 @@ import type { Reference } from '@kbn/content-management-utils'; import { EmbeddableStateWithType } from '@kbn/embeddable-plugin/common'; +import { PersistableControlGroupInput } from '@kbn/controls-plugin/common'; + import { DashboardAttributes, SavedDashboardPanel } from './content_management'; import { DashboardContainerInput, DashboardPanelMap } from './dashboard_container/types'; @@ -38,6 +40,7 @@ export type SharedDashboardState = Partial< * A partially parsed version of the Dashboard Attributes used for inject and extract logic for both the Dashboard Container and the Dashboard Saved Object. */ export type ParsedDashboardAttributesWithType = EmbeddableStateWithType & { + controlGroupInput?: PersistableControlGroupInput; panels: DashboardPanelMap; type: 'dashboard'; }; diff --git a/src/plugins/dashboard/public/dashboard_app/locator/locator.test.ts b/src/plugins/dashboard/public/dashboard_app/locator/locator.test.ts index fd2f64828899f..2b56acc719158 100644 --- a/src/plugins/dashboard/public/dashboard_app/locator/locator.test.ts +++ b/src/plugins/dashboard/public/dashboard_app/locator/locator.test.ts @@ -9,7 +9,9 @@ import { DashboardAppLocatorDefinition } from './locator'; import { hashedItemStore } from '@kbn/kibana-utils-plugin/public'; import { mockStorage } from '@kbn/kibana-utils-plugin/public/storage/hashed_item_store/mock'; +import { mockControlGroupInput } from '@kbn/controls-plugin/common/mocks'; import { FilterStateStore } from '@kbn/es-query'; +import { SerializableControlGroupInput } from '@kbn/controls-plugin/common'; describe('dashboard locator', () => { beforeEach(() => { @@ -191,18 +193,16 @@ describe('dashboard locator', () => { useHashedUrl: false, getDashboardFilterFields: async (dashboardId: string) => [], }); - const controlGroupState = { - autoApplySelections: false, - }; + const controlGroupInput = mockControlGroupInput() as unknown as SerializableControlGroupInput; const location = await definition.getLocation({ - controlGroupState, + controlGroupInput, }); expect(location).toMatchObject({ app: 'dashboards', path: `#/create?_g=()`, state: { - controlGroupState, + controlGroupInput, }, }); }); diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/controls_toolbar_button/add_data_control_button.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/controls_toolbar_button/add_data_control_button.tsx index b96f450e19bdc..e7c7daa2bcc27 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/controls_toolbar_button/add_data_control_button.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/controls_toolbar_button/add_data_control_button.tsx @@ -8,16 +8,16 @@ import React from 'react'; import { EuiContextMenuItem } from '@elastic/eui'; -import { ControlGroupApi } from '@kbn/controls-plugin/public'; +import { ControlGroupContainer } from '@kbn/controls-plugin/public'; import { getAddControlButtonTitle } from '../../_dashboard_app_strings'; import { useDashboardAPI } from '../../dashboard_app'; interface Props { closePopover: () => void; - controlGroupApi?: ControlGroupApi; + controlGroup: ControlGroupContainer; } -export const AddDataControlButton = ({ closePopover, controlGroupApi, ...rest }: Props) => { +export const AddDataControlButton = ({ closePopover, controlGroup, ...rest }: Props) => { const dashboard = useDashboardAPI(); const onSave = () => { dashboard.scrollToTop(); @@ -28,10 +28,9 @@ export const AddDataControlButton = ({ closePopover, controlGroupApi, ...rest }: {...rest} icon="plusInCircle" data-test-subj="controls-create-button" - disabled={!controlGroupApi} aria-label={getAddControlButtonTitle()} onClick={() => { - controlGroupApi?.openAddDataControlFlyout({ onSave }); + controlGroup.openAddDataControlFlyout({ onSave }); closePopover(); }} > diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/controls_toolbar_button/add_time_slider_control_button.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/controls_toolbar_button/add_time_slider_control_button.tsx index 9cb9b1b82f9da..a3a9cf7ce73d8 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/controls_toolbar_button/add_time_slider_control_button.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/controls_toolbar_button/add_time_slider_control_button.tsx @@ -7,12 +7,8 @@ */ import React, { useEffect, useState } from 'react'; -import { v4 as uuidv4 } from 'uuid'; import { EuiContextMenuItem } from '@elastic/eui'; -import type { ControlGroupApi } from '@kbn/controls-plugin/public'; -import { TIME_SLIDER_CONTROL } from '@kbn/controls-plugin/common'; - -import { apiHasType } from '@kbn/presentation-publishing'; +import { ControlGroupContainer, TIME_SLIDER_CONTROL } from '@kbn/controls-plugin/public'; import { getAddTimeSliderControlButtonTitle, getOnlyOneTimeSliderControlMsg, @@ -21,47 +17,40 @@ import { useDashboardAPI } from '../../dashboard_app'; interface Props { closePopover: () => void; - controlGroupApi?: ControlGroupApi; + controlGroup: ControlGroupContainer; } -export const AddTimeSliderControlButton = ({ closePopover, controlGroupApi, ...rest }: Props) => { +export const AddTimeSliderControlButton = ({ closePopover, controlGroup, ...rest }: Props) => { const [hasTimeSliderControl, setHasTimeSliderControl] = useState(false); const dashboard = useDashboardAPI(); useEffect(() => { - if (!controlGroupApi) { - return; - } - - const subscription = controlGroupApi.children$.subscribe((children) => { - const nextHasTimeSliderControl = Object.values(children).some((controlApi) => { - return apiHasType(controlApi) && controlApi.type === TIME_SLIDER_CONTROL; + const subscription = controlGroup.getInput$().subscribe(() => { + const childIds = controlGroup.getChildIds(); + const nextHasTimeSliderControl = childIds.some((id: string) => { + const child = controlGroup.getChild(id); + return child.type === TIME_SLIDER_CONTROL; }); - setHasTimeSliderControl(nextHasTimeSliderControl); + if (nextHasTimeSliderControl !== hasTimeSliderControl) { + setHasTimeSliderControl(nextHasTimeSliderControl); + } }); return () => { subscription.unsubscribe(); }; - }, [controlGroupApi]); + }, [controlGroup, hasTimeSliderControl, setHasTimeSliderControl]); return ( { - controlGroupApi?.addNewPanel({ - panelType: TIME_SLIDER_CONTROL, - initialState: { - grow: true, - width: 'large', - id: uuidv4(), - }, - }); + await controlGroup.addTimeSliderControl(); dashboard.scrollToTop(); closePopover(); }} data-test-subj="controls-create-timeslider-button" - disabled={!controlGroupApi || hasTimeSliderControl} + disabled={hasTimeSliderControl} toolTipContent={hasTimeSliderControl ? getOnlyOneTimeSliderControlMsg() : null} > {getAddTimeSliderControlButtonTitle()} diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/controls_toolbar_button/controls_toolbar_button.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/controls_toolbar_button/controls_toolbar_button.tsx index 6c6459266f7c3..ba90513a44c1d 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/controls_toolbar_button/controls_toolbar_button.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/controls_toolbar_button/controls_toolbar_button.tsx @@ -10,18 +10,18 @@ import React from 'react'; import { EuiContextMenuPanel, useEuiTheme } from '@elastic/eui'; import { ToolbarPopover } from '@kbn/shared-ux-button-toolbar'; +import type { ControlGroupContainer } from '@kbn/controls-plugin/public'; -import { ControlGroupApi } from '@kbn/controls-plugin/public'; import { getControlButtonTitle } from '../../_dashboard_app_strings'; import { AddDataControlButton } from './add_data_control_button'; import { AddTimeSliderControlButton } from './add_time_slider_control_button'; import { EditControlGroupButton } from './edit_control_group_button'; export function ControlsToolbarButton({ - controlGroupApi, + controlGroup, isDisabled, }: { - controlGroupApi?: ControlGroupApi; + controlGroup: ControlGroupContainer; isDisabled?: boolean; }) { const { euiTheme } = useEuiTheme(); @@ -43,17 +43,17 @@ export function ControlsToolbarButton({ items={[ , , , ]} diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/controls_toolbar_button/edit_control_group_button.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/controls_toolbar_button/edit_control_group_button.tsx index 5f093b2967d39..3563d87f5cf81 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/controls_toolbar_button/edit_control_group_button.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/controls_toolbar_button/edit_control_group_button.tsx @@ -8,24 +8,23 @@ import React from 'react'; import { EuiContextMenuItem } from '@elastic/eui'; -import { ControlGroupApi } from '@kbn/controls-plugin/public'; +import { ControlGroupContainer } from '@kbn/controls-plugin/public'; import { getEditControlGroupButtonTitle } from '../../_dashboard_app_strings'; interface Props { closePopover: () => void; - controlGroupApi?: ControlGroupApi; + controlGroup: ControlGroupContainer; } -export const EditControlGroupButton = ({ closePopover, controlGroupApi, ...rest }: Props) => { +export const EditControlGroupButton = ({ closePopover, controlGroup, ...rest }: Props) => { return ( { - controlGroupApi?.onEdit(); + controlGroup.openEditControlGroupFlyout(); closePopover(); }} > diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_editing_toolbar.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_editing_toolbar.tsx index 17d8ced554948..579d6d17d3a94 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_editing_toolbar.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_editing_toolbar.tsx @@ -13,7 +13,6 @@ import { useEuiTheme } from '@elastic/eui'; import { AddFromLibraryButton, Toolbar, ToolbarButton } from '@kbn/shared-ux-button-toolbar'; import { BaseVisType, VisTypeAlias } from '@kbn/visualizations-plugin/public'; -import { useStateFromPublishingSubject } from '@kbn/presentation-publishing'; import { getCreateVisualizationButtonTitle } from '../_dashboard_app_strings'; import { EditorMenu } from './editor_menu'; import { useDashboardAPI } from '../dashboard_app'; @@ -83,7 +82,6 @@ export function DashboardEditingToolbar({ isDisabled }: { isDisabled?: boolean } * dismissNotification: Optional, if not passed a toast will appear in the dashboard */ - const controlGroupApi = useStateFromPublishingSubject(dashboard.controlGroupApi$); const extraButtons = [ , , - , ]; + if (dashboard.controlGroup) { + extraButtons.push( + + ); + } return (
void; showResetChange?: boolean; }) => { - const isMounted = useMountedState(); - const [isSaveInProgress, setIsSaveInProgress] = useState(false); /** @@ -102,7 +99,6 @@ export const useDashboardMenuItems = ({ * (1) reset the dashboard to the last saved state, and * (2) if `switchToViewMode` is `true`, set the dashboard to view mode. */ - const [isResetting, setIsResetting] = useState(false); const resetChanges = useCallback( (switchToViewMode: boolean = false) => { dashboard.clearOverlays(); @@ -117,17 +113,13 @@ export const useDashboardMenuItems = ({ return; } confirmDiscardUnsavedChanges(() => { - batch(async () => { - setIsResetting(true); - await dashboard.asyncResetToLastSavedState(); - if (isMounted()) { - setIsResetting(false); - switchModes?.(); - } + batch(() => { + dashboard.resetToLastSavedState(); + switchModes?.(); }); }, viewMode); }, - [dashboard, dashboardBackup, hasUnsavedChanges, viewMode, isMounted] + [dashboard, dashboardBackup, hasUnsavedChanges, viewMode] ); /** @@ -198,8 +190,7 @@ export const useDashboardMenuItems = ({ switchToViewMode: { ...topNavStrings.switchToViewMode, id: 'cancel', - disableButton: disableTopNav || !lastSavedId || isResetting, - isLoading: isResetting, + disableButton: disableTopNav || !lastSavedId, testId: 'dashboardViewOnlyMode', run: () => resetChanges(true), } as TopNavMenuData, @@ -235,7 +226,6 @@ export const useDashboardMenuItems = ({ dashboardBackup, quickSaveDashboard, resetChanges, - isResetting, ]); const resetChangesMenuItem = useMemo(() => { @@ -244,22 +234,12 @@ export const useDashboardMenuItems = ({ id: 'reset', testId: 'dashboardDiscardChangesMenuItem', disableButton: - isResetting || !hasUnsavedChanges || hasOverlays || (viewMode === ViewMode.EDIT && (isSaveInProgress || !lastSavedId)), - isLoading: isResetting, run: () => resetChanges(), }; - }, [ - hasOverlays, - lastSavedId, - resetChanges, - viewMode, - isSaveInProgress, - hasUnsavedChanges, - isResetting, - ]); + }, [hasOverlays, lastSavedId, resetChanges, viewMode, isSaveInProgress, hasUnsavedChanges]); /** * Build ordered menus for view and edit mode. diff --git a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid.test.tsx b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid.test.tsx index 91fa453e7c5f9..93f25962a0916 100644 --- a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid.test.tsx +++ b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid.test.tsx @@ -44,7 +44,7 @@ jest.mock('./dashboard_grid_item', () => { }; }); -const createAndMountDashboardGrid = async () => { +const createAndMountDashboardGrid = () => { const dashboardContainer = buildMockDashboard({ overrides: { panels: { @@ -61,7 +61,6 @@ const createAndMountDashboardGrid = async () => { }, }, }); - await dashboardContainer.untilContainerInitialized(); const component = mountWithIntl( @@ -71,20 +70,20 @@ const createAndMountDashboardGrid = async () => { }; test('renders DashboardGrid', async () => { - const { component } = await createAndMountDashboardGrid(); + const { component } = createAndMountDashboardGrid(); const panelElements = component.find('GridItem'); expect(panelElements.length).toBe(2); }); test('renders DashboardGrid with no visualizations', async () => { - const { dashboardContainer, component } = await createAndMountDashboardGrid(); + const { dashboardContainer, component } = createAndMountDashboardGrid(); dashboardContainer.updateInput({ panels: {} }); component.update(); expect(component.find('GridItem').length).toBe(0); }); test('DashboardGrid removes panel when removed from container', async () => { - const { dashboardContainer, component } = await createAndMountDashboardGrid(); + const { dashboardContainer, component } = createAndMountDashboardGrid(); const originalPanels = dashboardContainer.getInput().panels; const filteredPanels = { ...originalPanels }; delete filteredPanels['1']; @@ -95,7 +94,7 @@ test('DashboardGrid removes panel when removed from container', async () => { }); test('DashboardGrid renders expanded panel', async () => { - const { dashboardContainer, component } = await createAndMountDashboardGrid(); + const { dashboardContainer, component } = createAndMountDashboardGrid(); dashboardContainer.setExpandedPanelId('1'); component.update(); // Both panels should still exist in the dom, so nothing needs to be re-fetched once minimized. @@ -113,7 +112,7 @@ test('DashboardGrid renders expanded panel', async () => { }); test('DashboardGrid renders focused panel', async () => { - const { dashboardContainer, component } = await createAndMountDashboardGrid(); + const { dashboardContainer, component } = createAndMountDashboardGrid(); dashboardContainer.setFocusedPanelId('2'); component.update(); // Both panels should still exist in the dom, so nothing needs to be re-fetched once minimized. diff --git a/src/plugins/dashboard/public/dashboard_container/component/viewport/dashboard_viewport.tsx b/src/plugins/dashboard/public/dashboard_container/component/viewport/dashboard_viewport.tsx index a3ffb5bfcdd38..cc0397a5af1e3 100644 --- a/src/plugins/dashboard/public/dashboard_container/component/viewport/dashboard_viewport.tsx +++ b/src/plugins/dashboard/public/dashboard_container/component/viewport/dashboard_viewport.tsx @@ -9,19 +9,12 @@ import { debounce } from 'lodash'; import classNames from 'classnames'; import useResizeObserver from 'use-resize-observer/polyfilled'; -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; import { EuiPortal } from '@elastic/eui'; -import { ReactEmbeddableRenderer, ViewMode } from '@kbn/embeddable-plugin/public'; +import { ViewMode } from '@kbn/embeddable-plugin/public'; import { ExitFullScreenButton } from '@kbn/shared-ux-button-exit-full-screen'; -import { - ControlGroupApi, - ControlGroupRuntimeState, - ControlGroupSerializedState, -} from '@kbn/controls-plugin/public'; -import { CONTROL_GROUP_TYPE } from '@kbn/controls-plugin/common'; -import { useStateFromPublishingSubject } from '@kbn/presentation-publishing'; import { DashboardGrid } from '../grid'; import { useDashboardContainer } from '../../embeddable/dashboard_container'; import { DashboardEmptyScreen } from '../empty_screen/dashboard_empty_screen'; @@ -41,11 +34,23 @@ export const useDebouncedWidthObserver = (skipDebounce = false, wait = 100) => { }; export const DashboardViewportComponent = () => { + const controlsRoot = useRef(null); + const dashboard = useDashboardContainer(); - const controlGroupApi = useStateFromPublishingSubject(dashboard.controlGroupApi$); + /** + * Render Control group + */ + const controlGroup = dashboard.controlGroup; + useEffect(() => { + if (controlGroup && controlsRoot.current) controlGroup.render(controlsRoot.current); + }, [controlGroup]); + const panelCount = Object.keys(dashboard.select((state) => state.explicitInput.panels)).length; - const [hasControls, setHasControls] = useState(false); + const controlCount = Object.keys( + controlGroup?.select((state) => state.explicitInput.panels) ?? {} + ).length; + const viewMode = dashboard.select((state) => state.explicitInput.viewMode); const dashboardTitle = dashboard.select((state) => state.explicitInput.title); const useMargins = dashboard.select((state) => state.explicitInput.useMargins); @@ -60,59 +65,17 @@ export const DashboardViewportComponent = () => { 'dshDashboardViewport--panelExpanded': Boolean(expandedPanelId), }); - useEffect(() => { - if (!controlGroupApi) { - return; - } - const subscription = controlGroupApi.children$.subscribe((children) => { - setHasControls(Object.keys(children).length > 0); - }); - return () => { - subscription.unsubscribe(); - }; - }, [controlGroupApi]); - - const [dashboardInitialized, setDashboardInitialized] = useState(false); - useEffect(() => { - let ignore = false; - dashboard.untilContainerInitialized().then(() => { - if (!ignore) { - setDashboardInitialized(true); - } - }); - return () => { - ignore = true; - }; - }, [dashboard]); - return (
- {viewMode !== ViewMode.PRINT ? ( -
- - key={dashboard.getInput().id} - hidePanelChrome={true} - panelProps={{ hideLoader: true }} - type={CONTROL_GROUP_TYPE} - maybeId={'control_group'} - getParentApi={() => { - return { - ...dashboard, - getSerializedStateForChild: dashboard.getSerializedStateForControlGroup, - getRuntimeStateForChild: dashboard.getRuntimeStateForControlGroup, - }; - }} - onApiAvailable={(api) => dashboard.setControlGroupApi(api)} - /> -
+ {controlGroup && viewMode !== ViewMode.PRINT ? ( +
0 ? 'dshDashboardViewport-controls' : ''} + ref={controlsRoot} + /> ) : null} {panelCount === 0 && }
{ > {/* Wait for `viewportWidth` to actually be set before rendering the dashboard grid - otherwise, there is a race condition where the panels can end up being squashed */} - {viewportWidth !== 0 && dashboardInitialized && ( - - )} + {viewportWidth !== 0 && }
); diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/api/run_save_functions.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/api/run_save_functions.tsx index b8ee1cca82156..215c3e7b99e7d 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/api/run_save_functions.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/api/run_save_functions.tsx @@ -7,6 +7,7 @@ */ import type { Reference } from '@kbn/content-management-utils'; +import type { PersistableControlGroupInput } from '@kbn/controls-plugin/common'; import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; import { EmbeddableInput, @@ -88,17 +89,13 @@ export async function runQuickSave(this: DashboardContainer) { const { panels: nextPanels, references } = await serializeAllPanelState(this); const dashboardStateToSave: DashboardContainerInput = { ...currentState, panels: nextPanels }; let stateToSave: SavedDashboardInput = dashboardStateToSave; - const controlGroupApi = this.controlGroupApi$.value; - let controlGroupReferences: Reference[] | undefined; - if (controlGroupApi) { - const { rawState: controlGroupSerializedState, references: extractedReferences } = - await controlGroupApi.serializeState(); - controlGroupReferences = extractedReferences; - stateToSave = { ...stateToSave, controlGroupInput: controlGroupSerializedState }; + let persistableControlGroupInput: PersistableControlGroupInput | undefined; + if (this.controlGroup) { + persistableControlGroupInput = this.controlGroup.getPersistableInput(); + stateToSave = { ...stateToSave, controlGroupInput: persistableControlGroupInput }; } const saveResult = await saveDashboardState({ - controlGroupReferences, panelReferences: references, currentState: stateToSave, saveOptions: {}, @@ -108,6 +105,9 @@ export async function runQuickSave(this: DashboardContainer) { this.savedObjectReferences = saveResult.references ?? []; this.dispatch.setLastSavedInput(dashboardStateToSave); this.saveNotification$.next(); + if (this.controlGroup && persistableControlGroupInput) { + this.controlGroup.setSavedState(persistableControlGroupInput); + } return saveResult; } @@ -180,20 +180,19 @@ export async function runInteractiveSave(this: DashboardContainer, interactionMo stateFromSaveModal.tags = newTags; } - let dashboardStateToSave: SavedDashboardInput = { + let dashboardStateToSave: DashboardContainerInput & { + controlGroupInput?: PersistableControlGroupInput; + } = { ...currentState, ...stateFromSaveModal, }; - const controlGroupApi = this.controlGroupApi$.value; - let controlGroupReferences: Reference[] | undefined; - if (controlGroupApi) { - const { rawState: controlGroupSerializedState, references } = - await controlGroupApi.serializeState(); - controlGroupReferences = references; + let persistableControlGroupInput: PersistableControlGroupInput | undefined; + if (this.controlGroup) { + persistableControlGroupInput = this.controlGroup.getPersistableInput(); dashboardStateToSave = { ...dashboardStateToSave, - controlGroupInput: controlGroupSerializedState, + controlGroupInput: persistableControlGroupInput, }; } @@ -226,7 +225,6 @@ export async function runInteractiveSave(this: DashboardContainer, interactionMo const beforeAddTime = window.performance.now(); const saveResult = await saveDashboardState({ - controlGroupReferences, panelReferences: references, saveOptions, currentState: { @@ -253,6 +251,9 @@ export async function runInteractiveSave(this: DashboardContainer, interactionMo batch(() => { this.dispatch.setStateFromSaveModal(stateFromSaveModal); this.dispatch.setLastSavedInput(dashboardStateToSave); + if (this.controlGroup && persistableControlGroupInput) { + this.controlGroup.setSavedState(persistableControlGroupInput); + } }); } diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/create/controls/dashboard_control_group_integration.test.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/create/controls/dashboard_control_group_integration.test.ts index 84b9d8dbea7b0..148c409e8d702 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/create/controls/dashboard_control_group_integration.test.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/create/controls/dashboard_control_group_integration.test.ts @@ -6,9 +6,11 @@ * Side Public License, v 1. */ +import { mockControlGroupInput } from '@kbn/controls-plugin/common/mocks'; +import { ControlGroupContainer } from '@kbn/controls-plugin/public/control_group/embeddable/control_group_container'; import { Filter } from '@kbn/es-query'; +import { ReduxToolsPackage } from '@kbn/presentation-util-plugin/public'; import { combineDashboardFiltersWithControlGroupFilters } from './dashboard_control_group_integration'; -import { BehaviorSubject } from 'rxjs'; jest.mock('@kbn/controls-plugin/public/control_group/embeddable/control_group_container'); @@ -49,41 +51,46 @@ const testFilter3: Filter = { }, }; -describe('combineDashboardFiltersWithControlGroupFilters', () => { - it('Combined filter pills do not get overwritten', async () => { - const dashboardFilterPills = [testFilter1, testFilter2]; - const mockControlGroupApi = { - filters$: new BehaviorSubject([]), - }; - const combinedFilters = combineDashboardFiltersWithControlGroupFilters( - dashboardFilterPills, - mockControlGroupApi - ); - expect(combinedFilters).toEqual(dashboardFilterPills); - }); +const mockControlGroupContainer = new ControlGroupContainer( + { getTools: () => {} } as unknown as ReduxToolsPackage, + mockControlGroupInput() +); - it('Combined control filters do not get overwritten', async () => { - const controlGroupFilters = [testFilter1, testFilter2]; - const mockControlGroupApi = { - filters$: new BehaviorSubject(controlGroupFilters), - }; - const combinedFilters = combineDashboardFiltersWithControlGroupFilters( - [] as Filter[], - mockControlGroupApi - ); - expect(combinedFilters).toEqual(controlGroupFilters); - }); +describe('Test dashboard control group', () => { + describe('Combine dashboard filters with control group filters test', () => { + it('Combined filter pills do not get overwritten', async () => { + const dashboardFilterPills = [testFilter1, testFilter2]; + mockControlGroupContainer.getOutput = jest.fn().mockReturnValue({ filters: [] }); + const combinedFilters = combineDashboardFiltersWithControlGroupFilters( + dashboardFilterPills, + mockControlGroupContainer + ); + expect(combinedFilters).toEqual(dashboardFilterPills); + }); + + it('Combined control filters do not get overwritten', async () => { + const controlGroupFilters = [testFilter1, testFilter2]; + mockControlGroupContainer.getOutput = jest + .fn() + .mockReturnValue({ filters: controlGroupFilters }); + const combinedFilters = combineDashboardFiltersWithControlGroupFilters( + [] as Filter[], + mockControlGroupContainer + ); + expect(combinedFilters).toEqual(controlGroupFilters); + }); - it('Combined dashboard filter pills and control filters do not get overwritten', async () => { - const dashboardFilterPills = [testFilter1, testFilter2]; - const controlGroupFilters = [testFilter3]; - const mockControlGroupApi = { - filters$: new BehaviorSubject(controlGroupFilters), - }; - const combinedFilters = combineDashboardFiltersWithControlGroupFilters( - dashboardFilterPills, - mockControlGroupApi - ); - expect(combinedFilters).toEqual(dashboardFilterPills.concat(controlGroupFilters)); + it('Combined dashboard filter pills and control filters do not get overwritten', async () => { + const dashboardFilterPills = [testFilter1, testFilter2]; + const controlGroupFilters = [testFilter3]; + mockControlGroupContainer.getOutput = jest + .fn() + .mockReturnValue({ filters: controlGroupFilters }); + const combinedFilters = combineDashboardFiltersWithControlGroupFilters( + dashboardFilterPills, + mockControlGroupContainer + ); + expect(combinedFilters).toEqual(dashboardFilterPills.concat(controlGroupFilters)); + }); }); }); diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/create/controls/dashboard_control_group_integration.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/create/controls/dashboard_control_group_integration.ts index 6267f6a27a2cc..675ea42634506 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/create/controls/dashboard_control_group_integration.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/create/controls/dashboard_control_group_integration.ts @@ -6,95 +6,114 @@ * Side Public License, v 1. */ -import { COMPARE_ALL_OPTIONS, compareFilters, type Filter } from '@kbn/es-query'; -import { - BehaviorSubject, - combineLatest, - distinctUntilChanged, - map, - of, - skip, - startWith, - switchMap, -} from 'rxjs'; -import { PublishesFilters, PublishingSubject } from '@kbn/presentation-publishing'; +import { ControlGroupInput } from '@kbn/controls-plugin/common'; +import { ControlGroupContainer } from '@kbn/controls-plugin/public'; +import { compareFilters, COMPARE_ALL_OPTIONS, type Filter } from '@kbn/es-query'; +import { combineCompatibleChildrenApis } from '@kbn/presentation-containers'; +import { apiPublishesDataLoading, PublishesDataLoading } from '@kbn/presentation-publishing'; +import deepEqual from 'fast-deep-equal'; +import { isEqual } from 'lodash'; +import { distinctUntilChanged, Observable, skip } from 'rxjs'; +import { DashboardContainerInput } from '../../../../../common'; import { DashboardContainer } from '../../dashboard_container'; -export function startSyncingDashboardControlGroup(dashboard: DashboardContainer) { - const controlGroupFilters$ = dashboard.controlGroupApi$.pipe( - switchMap((controlGroupApi) => (controlGroupApi ? controlGroupApi.filters$ : of(undefined))) - ); - const controlGroupTimeslice$ = dashboard.controlGroupApi$.pipe( - switchMap((controlGroupApi) => (controlGroupApi ? controlGroupApi.timeslice$ : of(undefined))) - ); +interface DiffChecks { + [key: string]: (a?: unknown, b?: unknown) => boolean; +} - // -------------------------------------------------------------------------------------- - // dashboard.unifiedSearchFilters$ - // -------------------------------------------------------------------------------------- - const unifiedSearchFilters$ = new BehaviorSubject( - dashboard.getInput().filters - ); - dashboard.unifiedSearchFilters$ = unifiedSearchFilters$ as PublishingSubject< - Filter[] | undefined - >; - dashboard.publishingSubscription.add( - dashboard - .getInput$() - .pipe( - startWith(dashboard.getInput()), - map((input) => input.filters), - distinctUntilChanged((previous, current) => { - return compareFilters(previous ?? [], current ?? [], COMPARE_ALL_OPTIONS); - }) - ) - .subscribe((unifiedSearchFilters) => { - unifiedSearchFilters$.next(unifiedSearchFilters); - }) - ); +const distinctUntilDiffCheck = (a: T, b: T, diffChecks: DiffChecks) => + !(Object.keys(diffChecks) as Array) + .map((key) => deepEqual(a[key], b[key])) + .includes(false); + +type DashboardControlGroupCommonKeys = keyof Pick< + DashboardContainerInput | ControlGroupInput, + 'filters' | 'lastReloadRequestTime' | 'timeRange' | 'query' +>; + +export function startSyncingDashboardControlGroup(this: DashboardContainer) { + if (!this.controlGroup) return; - // -------------------------------------------------------------------------------------- - // Set dashboard.filters$ to include unified search filters and control group filters - // -------------------------------------------------------------------------------------- - function getCombinedFilters() { - return combineDashboardFiltersWithControlGroupFilters( - dashboard.getInput().filters ?? [], - dashboard.controlGroupApi$.value - ); - } + const compareAllFilters = (a?: Filter[], b?: Filter[]) => + compareFilters(a ?? [], b ?? [], COMPARE_ALL_OPTIONS); - const filters$ = new BehaviorSubject(getCombinedFilters()); - dashboard.filters$ = filters$; + const dashboardRefetchDiff: DiffChecks = { + filters: (a, b) => compareAllFilters(a as Filter[], b as Filter[]), + timeRange: deepEqual, + query: deepEqual, + viewMode: deepEqual, + }; - dashboard.publishingSubscription.add( - combineLatest([dashboard.unifiedSearchFilters$, controlGroupFilters$]).subscribe(() => { - filters$.next(getCombinedFilters()); - }) + // pass down any pieces of input needed to refetch or force refetch data for the controls + this.integrationSubscriptions.add( + (this.getInput$() as Readonly>) + .pipe( + distinctUntilChanged((a, b) => + distinctUntilDiffCheck(a, b, dashboardRefetchDiff) + ) + ) + .subscribe(() => { + const newInput: { [key: string]: unknown } = {}; + (Object.keys(dashboardRefetchDiff) as DashboardControlGroupCommonKeys[]).forEach((key) => { + if ( + !dashboardRefetchDiff[key]?.(this.getInput()[key], this.controlGroup!.getInput()[key]) + ) { + newInput[key] = this.getInput()[key]; + } + }); + if (Object.keys(newInput).length > 0) { + this.controlGroup!.updateInput(newInput); + } + }) ); - // -------------------------------------------------------------------------------------- // when control group outputs filters, force a refresh! - // -------------------------------------------------------------------------------------- - dashboard.publishingSubscription.add( - controlGroupFilters$ + this.integrationSubscriptions.add( + this.controlGroup + .getOutput$() .pipe( + distinctUntilChanged(({ filters: filtersA }, { filters: filtersB }) => + compareAllFilters(filtersA, filtersB) + ), skip(1) // skip first filter output because it will have been applied in initialize ) - .subscribe(() => dashboard.forceRefresh(false)) // we should not reload the control group when the control group output changes - otherwise, performance is severely impacted + .subscribe(() => this.forceRefresh(false)) // we should not reload the control group when the control group output changes - otherwise, performance is severely impacted ); - // -------------------------------------------------------------------------------------- - // when control group outputs timeslice, dispatch timeslice - // -------------------------------------------------------------------------------------- - dashboard.publishingSubscription.add( - controlGroupTimeslice$.subscribe((timeslice) => { - dashboard.dispatch.setTimeslice(timeslice); - }) + this.integrationSubscriptions.add( + this.controlGroup + .getOutput$() + .pipe( + distinctUntilChanged(({ timeslice: timesliceA }, { timeslice: timesliceB }) => + isEqual(timesliceA, timesliceB) + ) + ) + .subscribe(({ timeslice }) => { + if (!isEqual(timeslice, this.getInput().timeslice)) { + this.dispatch.setTimeslice(timeslice); + } + }) + ); + + // the Control Group needs to know when any dashboard children are loading in order to know when to move on to the next time slice when playing. + this.integrationSubscriptions.add( + combineCompatibleChildrenApis( + this, + 'dataLoading', + apiPublishesDataLoading, + false, + (childrenLoading) => childrenLoading.some(Boolean) + ) + .pipe(skip(1)) // skip the initial output of "false" + .subscribe((anyChildLoading) => + this.controlGroup?.anyControlOutputConsumerLoading$.next(anyChildLoading) + ) ); } export const combineDashboardFiltersWithControlGroupFilters = ( dashboardFilters: Filter[], - controlGroupApi?: PublishesFilters + controlGroup: ControlGroupContainer ): Filter[] => { - return [...dashboardFilters, ...(controlGroupApi?.filters$.value ?? [])]; + return [...dashboardFilters, ...(controlGroup.getOutput().filters ?? [])]; }; diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts index 12f513c1f417f..b9d2ff286023d 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts @@ -6,6 +6,8 @@ * Side Public License, v 1. */ +import { BehaviorSubject, Observable } from 'rxjs'; + import { ContactCardEmbeddable, ContactCardEmbeddableFactory, @@ -13,6 +15,11 @@ import { ContactCardEmbeddableOutput, CONTACT_CARD_EMBEDDABLE, } from '@kbn/embeddable-plugin/public/lib/test_samples'; +import { + ControlGroupInput, + ControlGroupContainer, + ControlGroupContainerFactory, +} from '@kbn/controls-plugin/public'; import { Filter } from '@kbn/es-query'; import { EmbeddablePackageState, ViewMode } from '@kbn/embeddable-plugin/public'; import { createKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; @@ -22,7 +29,6 @@ import { getSampleDashboardPanel } from '../../../mocks'; import { pluginServices } from '../../../services/plugin_services'; import { DashboardCreationOptions } from '../dashboard_container_factory'; import { DEFAULT_DASHBOARD_INPUT } from '../../../dashboard_constants'; -import { mockControlGroupApi } from '../../../mocks'; test("doesn't throw error when no data views are available", async () => { pluginServices.getServices().data.dataViews.defaultDataViewExists = jest @@ -410,7 +416,6 @@ test('creates new embeddable with incoming embeddable if id does not match exist }, }), }); - dashboard?.setControlGroupApi(mockControlGroupApi); // flush promises await new Promise((r) => setTimeout(r, 1)); @@ -471,7 +476,6 @@ test('creates new embeddable with specified size if size is provided', async () }, }), }); - dashboard?.setControlGroupApi(mockControlGroupApi); // flush promises await new Promise((r) => setTimeout(r, 1)); @@ -493,6 +497,42 @@ test('creates new embeddable with specified size if size is provided', async () expect(dashboard!.getState().explicitInput.panels.new_panel.gridData.h).toBe(1); }); +test('creates a control group from the control group factory', async () => { + const mockControlGroupContainer = { + destroy: jest.fn(), + render: jest.fn(), + updateInput: jest.fn(), + getInput: jest.fn().mockReturnValue({}), + getInput$: jest.fn().mockReturnValue(new Observable()), + getOutput: jest.fn().mockReturnValue({}), + getOutput$: jest.fn().mockReturnValue(new Observable()), + onFiltersPublished$: new Observable(), + unsavedChanges: new BehaviorSubject(undefined), + } as unknown as ControlGroupContainer; + const mockControlGroupFactory = { + create: jest.fn().mockReturnValue(mockControlGroupContainer), + } as unknown as ControlGroupContainerFactory; + pluginServices.getServices().embeddable.getEmbeddableFactory = jest + .fn() + .mockReturnValue(mockControlGroupFactory); + await createDashboard({ + useControlGroupIntegration: true, + getInitialInput: () => ({ + controlGroupInput: { controlStyle: 'twoLine' } as unknown as ControlGroupInput, + }), + }); + // flush promises + await new Promise((r) => setTimeout(r, 1)); + expect(pluginServices.getServices().embeddable.getEmbeddableFactory).toHaveBeenCalledWith( + 'control_group' + ); + expect(mockControlGroupFactory.create).toHaveBeenCalledWith( + expect.objectContaining({ controlStyle: 'twoLine' }), + undefined, + { lastSavedInput: expect.objectContaining({ controlStyle: 'oneLine' }) } + ); +}); + /* * dashboard.getInput$() subscriptions are used to update: * 1) dashboard instance searchSessionId state @@ -527,7 +567,6 @@ test('searchSessionId is updated prior to child embeddable parent subscription e createSessionRestorationDataProvider: () => {}, } as unknown as DashboardCreationOptions['searchSessionSettings'], }); - dashboard?.setControlGroupApi(mockControlGroupApi); expect(dashboard).toBeDefined(); const embeddable = await dashboard!.addNewEmbeddable< ContactCardEmbeddableInput, diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts index 8e23540479535..158fc638adc3d 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts @@ -5,13 +5,38 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - +import { + ControlGroupInput, + CONTROL_GROUP_TYPE, + getDefaultControlGroupInput, + getDefaultControlGroupPersistableInput, +} from '@kbn/controls-plugin/common'; +import { + ControlGroupContainerFactory, + ControlGroupOutput, + type ControlGroupContainer, +} from '@kbn/controls-plugin/public'; import { GlobalQueryStateFromUrl, syncGlobalQueryStateWithUrl } from '@kbn/data-plugin/public'; -import { ViewMode } from '@kbn/embeddable-plugin/public'; -import { TimeRange } from '@kbn/es-query'; +import { EmbeddableFactory, isErrorEmbeddable, ViewMode } from '@kbn/embeddable-plugin/public'; +import { + AggregateQuery, + compareFilters, + COMPARE_ALL_OPTIONS, + Filter, + Query, + TimeRange, +} from '@kbn/es-query'; import { lazyLoadReduxToolsPackage } from '@kbn/presentation-util-plugin/public'; -import { cloneDeep, omit } from 'lodash'; -import { Subject } from 'rxjs'; +import deepEqual from 'fast-deep-equal'; +import { cloneDeep, identity, omit, pickBy } from 'lodash'; +import { + BehaviorSubject, + combineLatest, + distinctUntilChanged, + map, + startWith, + Subject, +} from 'rxjs'; import { v4 } from 'uuid'; import { DashboardContainerInput, @@ -35,11 +60,14 @@ import { startDiffingDashboardState } from '../../state/diffing/dashboard_diffin import { DashboardPublicState, UnsavedPanelState } from '../../types'; import { DashboardContainer } from '../dashboard_container'; import { DashboardCreationOptions } from '../dashboard_container_factory'; +import { + combineDashboardFiltersWithControlGroupFilters, + startSyncingDashboardControlGroup, +} from './controls/dashboard_control_group_integration'; import { startSyncingDashboardDataViews } from './data_views/sync_dashboard_data_views'; import { startQueryPerformanceTracking } from './performance/query_performance_tracking'; import { startDashboardSearchSessionIntegration } from './search_sessions/start_dashboard_search_session_integration'; import { syncUnifiedSearchState } from './unified_search/sync_dashboard_unified_search_state'; -import { PANELS_CONTROL_GROUP_KEY } from '../../../services/dashboard_backup/dashboard_backup_service'; /** * Builds a new Dashboard from scratch. @@ -134,13 +162,16 @@ export const initializeDashboard = async ({ loadDashboardReturn, untilDashboardReady, creationOptions, + controlGroup, }: { loadDashboardReturn: LoadDashboardReturn; untilDashboardReady: () => Promise; creationOptions?: DashboardCreationOptions; + controlGroup?: ControlGroupContainer; }) => { const { dashboardBackup, + embeddable: { getEmbeddableFactory }, dashboardCapabilities: { showWriteControls }, embeddable: { reactEmbeddableRegistryHasKey }, data: { @@ -160,6 +191,7 @@ export const initializeDashboard = async ({ searchSessionSettings, unifiedSearchSettings, validateLoadedSavedObject, + useControlGroupIntegration, useUnifiedSearchIntegration, useSessionStorageIntegration, } = creationOptions ?? {}; @@ -259,6 +291,11 @@ export const initializeDashboard = async ({ cloneDeep(combinedOverrideInput), 'controlGroupInput' ); + const initialControlGroupInput: ControlGroupInput | {} = { + ...(loadDashboardReturn?.dashboardInput?.controlGroupInput ?? {}), + ...(sessionStorageInput?.controlGroupInput ?? {}), + ...(overrideInput?.controlGroupInput ?? {}), + }; // Back up any view mode passed in explicitly. if (overrideInput?.viewMode) { @@ -275,7 +312,6 @@ export const initializeDashboard = async ({ // -------------------------------------------------------------------------------------- untilDashboardReady().then((dashboard) => { dashboard.savedObjectReferences = loadDashboardReturn?.references; - dashboard.controlGroupInput = loadDashboardReturn?.dashboardInput?.controlGroupInput; }); // -------------------------------------------------------------------------------------- @@ -438,13 +474,6 @@ export const initializeDashboard = async ({ // Set restored runtime state for react embeddables. // -------------------------------------------------------------------------------------- untilDashboardReady().then((dashboardContainer) => { - if (overrideInput?.controlGroupState) { - dashboardContainer.setRuntimeStateForChild( - PANELS_CONTROL_GROUP_KEY, - overrideInput.controlGroupState - ); - } - for (const idWithRuntimeState of Object.keys(runtimePanelsToRestore)) { const restoredRuntimeStateForChild = runtimePanelsToRestore[idWithRuntimeState]; if (!restoredRuntimeStateForChild) continue; @@ -452,6 +481,52 @@ export const initializeDashboard = async ({ } }); + // -------------------------------------------------------------------------------------- + // Start the control group integration. + // -------------------------------------------------------------------------------------- + if (useControlGroupIntegration) { + const controlsGroupFactory = getEmbeddableFactory< + ControlGroupInput, + ControlGroupOutput, + ControlGroupContainer + >(CONTROL_GROUP_TYPE) as EmbeddableFactory< + ControlGroupInput, + ControlGroupOutput, + ControlGroupContainer + > & { + create: ControlGroupContainerFactory['create']; + }; + const { filters, query, timeRange, viewMode, id } = initialDashboardInput; + const fullControlGroupInput = { + id: `control_group_${id ?? 'new_dashboard'}`, + ...getDefaultControlGroupInput(), + ...pickBy(initialControlGroupInput, identity), // undefined keys in initialInput should not overwrite defaults + timeRange, + viewMode, + filters, + query, + }; + + if (controlGroup) { + controlGroup.updateInputAndReinitialize(fullControlGroupInput); + } else { + const newControlGroup = await controlsGroupFactory?.create(fullControlGroupInput, this, { + lastSavedInput: + loadDashboardReturn?.dashboardInput?.controlGroupInput ?? + getDefaultControlGroupPersistableInput(), + }); + if (!newControlGroup || isErrorEmbeddable(newControlGroup)) { + throw new Error('Error in control group startup'); + } + controlGroup = newControlGroup; + } + + untilDashboardReady().then((dashboardContainer) => { + dashboardContainer.controlGroup = controlGroup; + startSyncingDashboardControlGroup.bind(dashboardContainer)(); + }); + } + // -------------------------------------------------------------------------------------- // Start the data views integration. // -------------------------------------------------------------------------------------- @@ -477,6 +552,63 @@ export const initializeDashboard = async ({ setTimeout(() => dashboard.dispatch.setAnimatePanelTransforms(true), 500) ); + // -------------------------------------------------------------------------------------- + // Set parentApi.filters$ to include dashboardContainer filters and control group filters + // -------------------------------------------------------------------------------------- + untilDashboardReady().then((dashboardContainer) => { + if (!dashboardContainer.controlGroup) { + return; + } + + function getCombinedFilters() { + return combineDashboardFiltersWithControlGroupFilters( + dashboardContainer.getInput().filters ?? [], + dashboardContainer.controlGroup! + ); + } + + const filters$ = new BehaviorSubject(getCombinedFilters()); + dashboardContainer.filters$ = filters$; + + const inputFilters$ = dashboardContainer.getInput$().pipe( + startWith(dashboardContainer.getInput()), + map((input) => input.filters), + distinctUntilChanged((previous, current) => { + return compareFilters(previous ?? [], current ?? [], COMPARE_ALL_OPTIONS); + }) + ); + + // Can not use onFiltersPublished$ directly since it does not have an intial value and + // combineLatest will not emit until each observable emits at least one value + const controlGroupFilters$ = dashboardContainer.controlGroup.onFiltersPublished$.pipe( + startWith(dashboardContainer.controlGroup.getOutput().filters) + ); + + dashboardContainer.integrationSubscriptions.add( + combineLatest([inputFilters$, controlGroupFilters$]).subscribe(() => { + filters$.next(getCombinedFilters()); + }) + ); + }); + + // -------------------------------------------------------------------------------------- + // Set up parentApi.query$ + // Can not use legacyEmbeddableToApi since query$ setting is delayed + // -------------------------------------------------------------------------------------- + untilDashboardReady().then((dashboardContainer) => { + const query$ = new BehaviorSubject( + dashboardContainer.getInput().query + ); + dashboardContainer.query$ = query$; + dashboardContainer.integrationSubscriptions.add( + dashboardContainer.getInput$().subscribe((input) => { + if (!deepEqual(query$.getValue() ?? [], input.query)) { + query$.next(input.query); + } + }) + ); + }); + // -------------------------------------------------------------------------------------- // Set up search sessions integration. // -------------------------------------------------------------------------------------- @@ -497,8 +629,7 @@ export const initializeDashboard = async ({ sessionIdToRestore ?? (existingSession && incomingEmbeddable ? existingSession : session.start()); - untilDashboardReady().then(async (container) => { - await container.untilContainerInitialized(); + untilDashboardReady().then((container) => { startDashboardSearchSessionIntegration.bind(container)( creationOptions?.searchSessionSettings ); diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/create/data_views/sync_dashboard_data_views.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/create/data_views/sync_dashboard_data_views.ts index 9de483bfb0376..3fd4c0df233cf 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/create/data_views/sync_dashboard_data_views.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/create/data_views/sync_dashboard_data_views.ts @@ -10,7 +10,7 @@ import { DataView } from '@kbn/data-views-plugin/common'; import { combineCompatibleChildrenApis } from '@kbn/presentation-containers'; import { apiPublishesDataViews, PublishesDataViews } from '@kbn/presentation-publishing'; import { uniqBy } from 'lodash'; -import { combineLatest, Observable, of, switchMap } from 'rxjs'; +import { combineLatest, map, Observable, of, switchMap } from 'rxjs'; import { pluginServices } from '../../../../services/plugin_services'; import { DashboardContainer } from '../../dashboard_container'; @@ -19,11 +19,19 @@ export function startSyncingDashboardDataViews(this: DashboardContainer) { data: { dataViews }, } = pluginServices.getServices(); - const controlGroupDataViewsPipe: Observable = this.controlGroupApi$.pipe( - switchMap((controlGroupApi) => { - return controlGroupApi ? controlGroupApi.dataViews : of([]); - }) - ); + const controlGroupDataViewsPipe: Observable = this.controlGroup + ? this.controlGroup.getOutput$().pipe( + map((output) => output.dataViewIds ?? []), + switchMap( + (dataViewIds) => + new Promise((resolve) => + Promise.all(dataViewIds.map((id) => dataViews.get(id))).then((nextDataViews) => + resolve(nextDataViews) + ) + ) + ) + ) + : of([]); const childDataViewsPipe = combineCompatibleChildrenApis( this, @@ -35,10 +43,7 @@ export function startSyncingDashboardDataViews(this: DashboardContainer) { return combineLatest([controlGroupDataViewsPipe, childDataViewsPipe]) .pipe( switchMap(([controlGroupDataViews, childDataViews]) => { - const allDataViews = [ - ...(controlGroupDataViews ? controlGroupDataViews : []), - ...childDataViews, - ]; + const allDataViews = controlGroupDataViews.concat(childDataViews); if (allDataViews.length === 0) { return (async () => { const defaultDataViewId = await dataViews.getDefaultId(); @@ -49,6 +54,7 @@ export function startSyncingDashboardDataViews(this: DashboardContainer) { }) ) .subscribe((newDataViews) => { + if (newDataViews[0].id) this.controlGroup?.setRelevantDataViewId(newDataViews[0].id); this.setAllDataViews(newDataViews); }); } diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.test.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.test.tsx index b6d77ac9b7822..ee2cc0dd961fd 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.test.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.test.tsx @@ -18,12 +18,7 @@ import { import type { TimeRange } from '@kbn/es-query'; import { mockedReduxEmbeddablePackage } from '@kbn/presentation-util-plugin/public/mocks'; -import { - buildMockDashboard, - getSampleDashboardInput, - getSampleDashboardPanel, - mockControlGroupApi, -} from '../../mocks'; +import { buildMockDashboard, getSampleDashboardInput, getSampleDashboardPanel } from '../../mocks'; import { pluginServices } from '../../services/plugin_services'; import { DashboardContainer } from './dashboard_container'; @@ -175,7 +170,6 @@ test('searchSessionId propagates to children', async () => { undefined, { lastSavedInput: sampleInput } ); - container?.setControlGroupApi(mockControlGroupApi); const embeddable = await container.addNewEmbeddable< ContactCardEmbeddableInput, ContactCardEmbeddableOutput, @@ -195,10 +189,11 @@ describe('getInheritedInput', () => { const dashboardTimeslice = [1688061910000, 1688062209000] as [number, number]; test('Should pass dashboard timeRange and timeslice to panel when panel does not have custom time range', async () => { - const container = buildMockDashboard(); - container.updateInput({ - timeRange: dashboardTimeRange, - timeslice: dashboardTimeslice, + const container = buildMockDashboard({ + overrides: { + timeRange: dashboardTimeRange, + timeslice: dashboardTimeslice, + }, }); const embeddable = await container.addNewEmbeddable( CONTACT_CARD_EMBEDDABLE, @@ -219,10 +214,11 @@ describe('getInheritedInput', () => { }); test('Should not pass dashboard timeRange and timeslice to panel when panel has custom time range', async () => { - const container = buildMockDashboard(); - container.updateInput({ - timeRange: dashboardTimeRange, - timeslice: dashboardTimeslice, + const container = buildMockDashboard({ + overrides: { + timeRange: dashboardTimeRange, + timeslice: dashboardTimeslice, + }, }); const embeddableTimeRange = { to: 'now', diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx index d1409a3a4b02e..585e0ff0b1ff6 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx @@ -8,6 +8,7 @@ import { METRIC_TYPE } from '@kbn/analytics'; import type { Reference } from '@kbn/content-management-utils'; +import type { ControlGroupContainer } from '@kbn/controls-plugin/public'; import type { I18nStart, KibanaExecutionContext, OverlayRef } from '@kbn/core/public'; import { type PublishingSubject, @@ -15,8 +16,6 @@ import { apiPublishesUnsavedChanges, getPanelTitle, PublishesViewMode, - PublishesDataLoading, - apiPublishesDataLoading, } from '@kbn/presentation-publishing'; import { RefreshInterval } from '@kbn/data-plugin/public'; import type { DataView } from '@kbn/data-views-plugin/public'; @@ -33,7 +32,7 @@ import { type EmbeddableOutput, type IEmbeddable, } from '@kbn/embeddable-plugin/public'; -import type { AggregateQuery, Filter, Query, TimeRange } from '@kbn/es-query'; +import type { Filter, Query, TimeRange } from '@kbn/es-query'; import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { HasRuntimeChildState, @@ -41,7 +40,6 @@ import { HasSerializedChildState, TrackContentfulRender, TracksQueryPerformance, - combineCompatibleChildrenApis, } from '@kbn/presentation-containers'; import { PanelPackage } from '@kbn/presentation-containers'; import { ReduxEmbeddableTools, ReduxToolsPackage } from '@kbn/presentation-util-plugin/public'; @@ -52,18 +50,14 @@ import { omit } from 'lodash'; import React, { createContext, useContext } from 'react'; import ReactDOM from 'react-dom'; import { batch } from 'react-redux'; -import { BehaviorSubject, Subject, Subscription, first, skipWhile, switchMap } from 'rxjs'; +import { BehaviorSubject, Subject, Subscription } from 'rxjs'; import { distinctUntilChanged, map } from 'rxjs'; import { v4 } from 'uuid'; import { PublishesSettings } from '@kbn/presentation-containers/interfaces/publishes_settings'; import { apiHasSerializableState } from '@kbn/presentation-containers/interfaces/serialized_state'; -import { ControlGroupApi, ControlGroupSerializedState } from '@kbn/controls-plugin/public'; import { DashboardLocatorParams, DASHBOARD_CONTAINER_TYPE } from '../..'; -import { DashboardAttributes, DashboardContainerInput, DashboardPanelState } from '../../../common'; -import { - getReferencesForControls, - getReferencesForPanelId, -} from '../../../common/dashboard_container/persistable_state/dashboard_container_references'; +import { DashboardContainerInput, DashboardPanelState } from '../../../common'; +import { getReferencesForPanelId } from '../../../common/dashboard_container/persistable_state/dashboard_container_references'; import { DASHBOARD_APP_ID, DASHBOARD_UI_METRIC_ID, @@ -90,10 +84,7 @@ import { showSettings, } from './api'; import { duplicateDashboardPanel } from './api/duplicate_dashboard_panel'; -import { - combineDashboardFiltersWithControlGroupFilters, - startSyncingDashboardControlGroup, -} from './create/controls/dashboard_control_group_integration'; +import { combineDashboardFiltersWithControlGroupFilters } from './create/controls/dashboard_control_group_integration'; import { initializeDashboard } from './create/create_dashboard'; import { DashboardCreationOptions, @@ -101,7 +92,6 @@ import { dashboardTypeDisplayName, } from './dashboard_container_factory'; import { getPanelAddedSuccessString } from '../../dashboard_app/_dashboard_app_strings'; -import { PANELS_CONTROL_GROUP_KEY } from '../../services/dashboard_backup/dashboard_backup_service'; export interface InheritedChildInput { filters: Filter[]; @@ -157,7 +147,7 @@ export class DashboardContainer public integrationSubscriptions: Subscription = new Subscription(); public publishingSubscription: Subscription = new Subscription(); public diffingSubscription: Subscription = new Subscription(); - public controlGroupApi$: PublishingSubject; + public controlGroup?: ControlGroupContainer; public settings: Record>; public searchSessionId?: string; @@ -166,7 +156,6 @@ export class DashboardContainer public reload$ = new Subject(); public timeRestore$: BehaviorSubject; public timeslice$: BehaviorSubject<[number, number] | undefined>; - public unifiedSearchFilters$?: PublishingSubject; public locator?: Pick, 'navigate' | 'getRedirectUrl'>; public readonly executionContext: KibanaExecutionContext; @@ -183,9 +172,6 @@ export class DashboardContainer private hadContentfulRender = false; private scrollPosition?: number; - // setup - public untilContainerInitialized: () => Promise; - // cleanup public stopSyncingWithUnifiedSearch?: () => void; private cleanupStateTools: () => void; @@ -211,7 +197,6 @@ export class DashboardContainer | undefined; // new embeddable framework public savedObjectReferences: Reference[] = []; - public controlGroupInput: DashboardAttributes['controlGroupInput'] | undefined; constructor( initialInput: DashboardContainerInput, @@ -222,43 +207,19 @@ export class DashboardContainer creationOptions?: DashboardCreationOptions, initialComponentState?: DashboardPublicState ) { - const controlGroupApi$ = new BehaviorSubject(undefined); - async function untilContainerInitialized(): Promise { - return new Promise((resolve) => { - controlGroupApi$ - .pipe( - skipWhile((controlGroupApi) => !controlGroupApi), - switchMap(async (controlGroupApi) => { - await controlGroupApi?.untilInitialized(); - }), - first() - ) - .subscribe(() => { - resolve(); - }); - }); - } - const { usageCollection, embeddable: { getEmbeddableFactory }, } = pluginServices.getServices(); - super( { ...initialInput, }, { embeddableLoaded: {} }, getEmbeddableFactory, - parent, - { - untilContainerInitialized, - } + parent ); - this.controlGroupApi$ = controlGroupApi$; - this.untilContainerInitialized = untilContainerInitialized; - this.trackPanelAddMetric = usageCollection.reportUiCounter?.bind( usageCollection, DASHBOARD_UI_METRIC_ID @@ -350,41 +311,7 @@ export class DashboardContainer DashboardContainerInput >(this.publishingSubscription, this, 'lastReloadRequestTime'); - startSyncingDashboardControlGroup(this); - this.executionContext = initialInput.executionContext; - - this.dataLoading = new BehaviorSubject(false); - this.publishingSubscription.add( - combineCompatibleChildrenApis( - this, - 'dataLoading', - apiPublishesDataLoading, - undefined, - // flatten method - (values) => { - return values.some((isLoading) => isLoading); - } - ).subscribe((isAtLeastOneChildLoading) => { - (this.dataLoading as BehaviorSubject).next(isAtLeastOneChildLoading); - }) - ); - - this.dataViews = new BehaviorSubject(this.getAllDataViews()); - - const query$ = new BehaviorSubject(this.getInput().query); - this.query$ = query$; - this.publishingSubscription.add( - this.getInput$().subscribe((input) => { - if (!deepEqual(query$.getValue() ?? [], input.query)) { - query$.next(input.query); - } - }) - ); - } - - public setControlGroupApi(controlGroupApi: ControlGroupApi) { - (this.controlGroupApi$ as BehaviorSubject).next(controlGroupApi); } public getAppContext() { @@ -470,10 +397,10 @@ export class DashboardContainer panels, } = this.input; - const combinedFilters = combineDashboardFiltersWithControlGroupFilters( - filters, - this.controlGroupApi$?.value - ); + let combinedFilters = filters; + if (this.controlGroup) { + combinedFilters = combineDashboardFiltersWithControlGroupFilters(filters, this.controlGroup); + } const hasCustomTimeRange = Boolean( (panels[id]?.explicitInput as Partial)?.timeRange ); @@ -502,6 +429,7 @@ export class DashboardContainer public destroy() { super.destroy(); this.cleanupStateTools(); + this.controlGroup?.destroy(); this.diffingSubscription.unsubscribe(); this.publishingSubscription.unsubscribe(); this.integrationSubscriptions.unsubscribe(); @@ -687,12 +615,16 @@ export class DashboardContainer public forceRefresh(refreshControlGroup: boolean = true) { this.dispatch.setLastReloadRequestTimeToNow({}); if (refreshControlGroup) { + this.controlGroup?.reload(); + // only reload all panels if this refresh does not come from the control group. this.reload$.next(); } } - public async asyncResetToLastSavedState() { + public onDataViewsUpdate$ = new Subject(); + + public resetToLastSavedState() { this.dispatch.resetToLastSavedInput({}); const { explicitInput: { timeRange, refreshInterval }, @@ -701,8 +633,8 @@ export class DashboardContainer }, } = this.getState(); - if (this.controlGroupApi$.value) { - await this.controlGroupApi$.value.asyncResetUnsavedChanges(); + if (this.controlGroup) { + this.controlGroup.resetToLastSavedState(); } // if we are using the unified search integration, we need to force reset the time picker. @@ -747,6 +679,7 @@ export class DashboardContainer const initializeResult = await initializeDashboard({ creationOptions: this.creationOptions, + controlGroup: this.controlGroup, untilDashboardReady, loadDashboardReturn, }); @@ -761,6 +694,9 @@ export class DashboardContainer omit(loadDashboardReturn?.dashboardInput, 'controlGroupInput') ); this.dispatch.setManaged(loadDashboardReturn?.managed); + if (this.controlGroup) { + this.controlGroup.setSavedState(loadDashboardReturn.dashboardInput?.controlGroupInput); + } this.dispatch.setAnimatePanelTransforms(false); // prevents panels from animating on navigate. this.dispatch.setLastSavedId(newSavedObjectId); this.setExpandedPanelId(undefined); @@ -784,7 +720,7 @@ export class DashboardContainer */ public setAllDataViews = (newDataViews: DataView[]) => { this.allDataViews = newDataViews; - (this.dataViews as BehaviorSubject).next(newDataViews); + this.onDataViewsUpdate$.next(newDataViews); }; public getExpandedPanelId = () => { @@ -807,6 +743,7 @@ export class DashboardContainer public clearOverlays = () => { this.dispatch.setHasOverlays(false); this.dispatch.setFocusedPanelId(undefined); + this.controlGroup?.closeAllFlyouts(); this.overlayRef?.close(); }; @@ -911,22 +848,6 @@ export class DashboardContainer }; }; - public getSerializedStateForControlGroup = () => { - return { - rawState: this.controlGroupInput - ? (this.controlGroupInput as ControlGroupSerializedState) - : ({ - controlStyle: 'oneLine', - chainingSystem: 'HIERARCHICAL', - showApplySelections: false, - panelsJSON: '{}', - ignoreParentSettingsJSON: - '{"ignoreFilters":false,"ignoreQuery":false,"ignoreTimerange":false,"ignoreValidations":false}', - } as ControlGroupSerializedState), - references: getReferencesForControls(this.savedObjectReferences), - }; - }; - private restoredRuntimeState: UnsavedPanelState | undefined = undefined; public setRuntimeStateForChild = (childId: string, state: object) => { const runtimeState = this.restoredRuntimeState ?? {}; @@ -937,10 +858,6 @@ export class DashboardContainer return this.restoredRuntimeState?.[childId]; }; - public getRuntimeStateForControlGroup = () => { - return this.getRuntimeStateForChild(PANELS_CONTROL_GROUP_KEY); - }; - public removePanel(id: string) { const { embeddable: { reactEmbeddableRegistryHasKey }, diff --git a/src/plugins/dashboard/public/dashboard_container/state/diffing/dashboard_diffing_integration.ts b/src/plugins/dashboard/public/dashboard_container/state/diffing/dashboard_diffing_integration.ts index 6d73e59856e28..89f71c074d9fd 100644 --- a/src/plugins/dashboard/public/dashboard_container/state/diffing/dashboard_diffing_integration.ts +++ b/src/plugins/dashboard/public/dashboard_container/state/diffing/dashboard_diffing_integration.ts @@ -5,10 +5,11 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ +import { PersistableControlGroupInput } from '@kbn/controls-plugin/common'; import { childrenUnsavedChanges$ } from '@kbn/presentation-containers'; import { omit } from 'lodash'; import { AnyAction, Middleware } from 'redux'; -import { combineLatest, debounceTime, skipWhile, startWith, switchMap } from 'rxjs'; +import { combineLatest, debounceTime, Observable, of, startWith, switchMap } from 'rxjs'; import { DashboardContainer, DashboardCreationOptions } from '../..'; import { DashboardContainerInput } from '../../../../common'; import { CHANGE_CHECK_DEBOUNCE } from '../../../dashboard_constants'; @@ -16,7 +17,6 @@ import { pluginServices } from '../../../services/plugin_services'; import { UnsavedPanelState } from '../../types'; import { dashboardContainerReducers } from '../dashboard_container_reducers'; import { isKeyEqualAsync, unsavedChangesDiffingFunctions } from './dashboard_diffing_functions'; -import { PANELS_CONTROL_GROUP_KEY } from '../../../services/dashboard_backup/dashboard_backup_service'; /** * An array of reducers which cannot cause unsaved changes. Unsaved changes only compares the explicit input @@ -111,12 +111,8 @@ export function startDiffingDashboardState( combineLatest([ dashboardUnsavedChanges, childrenUnsavedChanges$(this.children$), - this.controlGroupApi$.pipe( - skipWhile((controlGroupApi) => !controlGroupApi), - switchMap((controlGroupApi) => { - return controlGroupApi!.unsavedChanges; - }) - ), + this.controlGroup?.unsavedChanges ?? + (of(undefined) as Observable), ]).subscribe(([dashboardChanges, unsavedPanelState, controlGroupChanges]) => { // calculate unsaved changes const hasUnsavedChanges = @@ -129,11 +125,11 @@ export function startDiffingDashboardState( // backup unsaved changes if configured to do so if (creationOptions?.useSessionStorageIntegration) { - const reactEmbeddableChanges = unsavedPanelState ? { ...unsavedPanelState } : {}; - if (controlGroupChanges) { - reactEmbeddableChanges[PANELS_CONTROL_GROUP_KEY] = controlGroupChanges; - } - backupUnsavedChanges.bind(this)(dashboardChanges, reactEmbeddableChanges); + backupUnsavedChanges.bind(this)( + dashboardChanges, + unsavedPanelState ? unsavedPanelState : {}, + controlGroupChanges + ); } }) ); @@ -185,7 +181,8 @@ export async function getDashboardUnsavedChanges( function backupUnsavedChanges( this: DashboardContainer, dashboardChanges: Partial, - reactEmbeddableChanges: UnsavedPanelState + reactEmbeddableChanges: UnsavedPanelState, + controlGroupChanges: PersistableControlGroupInput | undefined ) { const { dashboardBackup } = pluginServices.getServices(); const dashboardStateToBackup = omit(dashboardChanges, keysToOmitFromSessionStorage); @@ -195,6 +192,7 @@ function backupUnsavedChanges( { ...dashboardStateToBackup, panels: dashboardChanges.panels, + controlGroupInput: controlGroupChanges, }, reactEmbeddableChanges ); diff --git a/src/plugins/dashboard/public/dashboard_container/types.ts b/src/plugins/dashboard/public/dashboard_container/types.ts index f3ca588aa20b1..c2c7cfb8aa083 100644 --- a/src/plugins/dashboard/public/dashboard_container/types.ts +++ b/src/plugins/dashboard/public/dashboard_container/types.ts @@ -6,11 +6,11 @@ * Side Public License, v 1. */ +import { SerializableControlGroupInput } from '@kbn/controls-plugin/common'; import type { ContainerOutput } from '@kbn/embeddable-plugin/public'; import type { ReduxEmbeddableState } from '@kbn/presentation-util-plugin/public'; import { SerializableRecord } from '@kbn/utility-types'; -import { ControlGroupRuntimeState } from '@kbn/controls-plugin/public'; import type { DashboardContainerInput, DashboardOptions } from '../../common'; import { SavedDashboardPanel } from '../../common/content_management'; @@ -125,7 +125,7 @@ export type DashboardLocatorParams = Partial< panels?: Array; // used SerializableRecord here to force the GridData type to be read as serializable /** - * Control group changes + * Control group input */ - controlGroupState?: Partial & SerializableRecord; // used SerializableRecord here to force the GridData type to be read as serializable + controlGroupInput?: SerializableControlGroupInput; }; diff --git a/src/plugins/dashboard/public/dashboard_top_nav/internal_dashboard_top_nav.tsx b/src/plugins/dashboard/public/dashboard_top_nav/internal_dashboard_top_nav.tsx index 86682acb4287f..5f6edc138aa13 100644 --- a/src/plugins/dashboard/public/dashboard_top_nav/internal_dashboard_top_nav.tsx +++ b/src/plugins/dashboard/public/dashboard_top_nav/internal_dashboard_top_nav.tsx @@ -15,6 +15,7 @@ import { getContextProvider as getPresentationUtilContextProvider, } from '@kbn/presentation-util-plugin/public'; import { ViewMode } from '@kbn/embeddable-plugin/public'; +import type { DataView } from '@kbn/data-views-plugin/public'; import { TopNavMenuBadgeProps, TopNavMenuProps } from '@kbn/navigation-plugin/public'; import { EuiBreadcrumb, @@ -28,7 +29,6 @@ import { import { MountPoint } from '@kbn/core/public'; import { getManagedContentBadge } from '@kbn/managed-content-badge'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useStateFromPublishingSubject } from '@kbn/presentation-publishing'; import { getDashboardTitle, leaveConfirmStrings, @@ -113,8 +113,16 @@ export function InternalDashboardTopNav({ const query = dashboard.select((state) => state.explicitInput.query); const title = dashboard.select((state) => state.explicitInput.title); + // store data views in state & subscribe to dashboard data view changes. + const [allDataViews, setAllDataViews] = useState([]); const [isPopoverOpen, setIsPopoverOpen] = useState(false); - const allDataViews = useStateFromPublishingSubject(dashboard.dataViews); + useEffect(() => { + setAllDataViews(dashboard.getAllDataViews()); + const subscription = dashboard.onDataViewsUpdate$.subscribe((dataViews) => + setAllDataViews(dataViews) + ); + return () => subscription.unsubscribe(); + }, [dashboard]); const dashboardTitle = useMemo(() => { return getDashboardTitle(title, viewMode, !lastSavedId); @@ -403,7 +411,7 @@ export function InternalDashboardTopNav({ screenTitle={title} useDefaultBehaviors={true} savedQueryId={savedQueryId} - indexPatterns={allDataViews ?? []} + indexPatterns={allDataViews} saveQueryMenuVisibility={allowSaveQuery ? 'allowed_by_app_privilege' : 'globally_managed'} appName={LEGACY_DASHBOARD_APP_ID} visible={viewMode !== ViewMode.PRINT} diff --git a/src/plugins/dashboard/public/mocks.tsx b/src/plugins/dashboard/public/mocks.tsx index 4a75d1a08b996..d447015b2b1a6 100644 --- a/src/plugins/dashboard/public/mocks.tsx +++ b/src/plugins/dashboard/public/mocks.tsx @@ -9,8 +9,6 @@ import { EmbeddableInput, ViewMode } from '@kbn/embeddable-plugin/public'; import { mockedReduxEmbeddablePackage } from '@kbn/presentation-util-plugin/public/mocks'; -import { ControlGroupApi } from '@kbn/controls-plugin/public'; -import { BehaviorSubject } from 'rxjs'; import { DashboardContainerInput, DashboardPanelState } from '../common'; import { DashboardContainer } from './dashboard_container/embeddable/dashboard_container'; import { DashboardStart } from './plugin'; @@ -74,15 +72,6 @@ export function setupIntersectionObserverMock({ }); } -export const mockControlGroupApi = { - untilInitialized: async () => {}, - filters$: new BehaviorSubject(undefined), - query$: new BehaviorSubject(undefined), - timeslice$: new BehaviorSubject(undefined), - dataViews: new BehaviorSubject(undefined), - unsavedChanges: new BehaviorSubject(undefined), -} as unknown as ControlGroupApi; - export function buildMockDashboard({ overrides, savedObjectId, @@ -100,7 +89,6 @@ export function buildMockDashboard({ undefined, { lastSavedInput: initialInput, lastSavedId: savedObjectId } ); - dashboardContainer?.setControlGroupApi(mockControlGroupApi); return dashboardContainer; } diff --git a/src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup_service.ts b/src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup_service.ts index 54486ece0970a..f97d88fd1c4fe 100644 --- a/src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup_service.ts +++ b/src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup_service.ts @@ -23,7 +23,6 @@ import { backupServiceStrings } from '../../dashboard_container/_dashboard_conta import { UnsavedPanelState } from '../../dashboard_container/types'; export const DASHBOARD_PANELS_UNSAVED_ID = 'unsavedDashboard'; -export const PANELS_CONTROL_GROUP_KEY = 'controlGroup'; const DASHBOARD_PANELS_SESSION_KEY = 'dashboardPanels'; const DASHBOARD_VIEWMODE_LOCAL_KEY = 'dashboardViewMode'; @@ -113,7 +112,6 @@ class DashboardBackupService implements DashboardBackupServiceType { const panels = this.sessionStorage.get(DASHBOARD_PANELS_SESSION_KEY)?.[this.activeSpaceId]?.[ id ] as UnsavedPanelState | undefined; - return { dashboardState, panels }; } catch (e) { this.notifications.toasts.addDanger({ diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/dashboard_content_management_service.ts b/src/plugins/dashboard/public/services/dashboard_content_management/dashboard_content_management_service.ts index eccd68b6952c0..2b2835e2a2420 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/dashboard_content_management_service.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management/dashboard_content_management_service.ts @@ -56,15 +56,8 @@ export const dashboardContentManagementServiceFactory: DashboardContentManagemen contentManagement, savedObjectsTagging, }), - saveDashboardState: ({ - controlGroupReferences, - currentState, - saveOptions, - lastSavedId, - panelReferences, - }) => + saveDashboardState: ({ currentState, saveOptions, lastSavedId, panelReferences }) => saveDashboardState({ - controlGroupReferences, data, embeddable, saveOptions, diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/load_dashboard_state.ts b/src/plugins/dashboard/public/services/dashboard_content_management/lib/load_dashboard_state.ts index 55ee72c5abbef..cabd1542efbb2 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/lib/load_dashboard_state.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management/lib/load_dashboard_state.ts @@ -12,6 +12,7 @@ import { Filter, Query } from '@kbn/es-query'; import { ViewMode } from '@kbn/embeddable-plugin/public'; import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/public'; import { cleanFiltersForSerialize } from '@kbn/presentation-util-plugin/public'; +import { rawControlGroupAttributesToControlGroupInput } from '@kbn/controls-plugin/common'; import { parseSearchSourceJSON, injectSearchSourceReferences } from '@kbn/data-plugin/public'; import { @@ -186,7 +187,9 @@ export const loadDashboardState = async ({ viewMode: ViewMode.VIEW, // dashboards loaded from saved object default to view mode. If it was edited recently, the view mode from session storage will override this. tags: savedObjectsTagging.getTagIdsFromReferences?.(references) ?? [], - controlGroupInput: attributes.controlGroupInput, + controlGroupInput: + attributes.controlGroupInput && + rawControlGroupAttributesToControlGroupInput(attributes.controlGroupInput), version: convertNumberToDashboardVersion(version), }, diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.test.ts b/src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.test.ts index 0487f14e699c6..1878344b630fc 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.test.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.test.ts @@ -6,6 +6,9 @@ * Side Public License, v 1. */ +import { ControlGroupInput } from '@kbn/controls-plugin/common'; +import { controlGroupInputBuilder } from '@kbn/controls-plugin/public'; + import { getSampleDashboardInput, getSampleDashboardPanel } from '../../../mocks'; import { DashboardEmbeddableService } from '../../embeddable/types'; import { SavedDashboardInput } from '../types'; @@ -29,6 +32,23 @@ describe('Migrate dashboard input', () => { panel3: getSampleDashboardPanel({ type: 'ultraDiscover', explicitInput: { id: 'panel3' } }), panel4: getSampleDashboardPanel({ type: 'ultraDiscover', explicitInput: { id: 'panel4' } }), }; + const controlGroupInput = { chainingSystem: 'NONE', panels: {} } as ControlGroupInput; + controlGroupInputBuilder.addOptionsListControl(controlGroupInput, { + dataViewId: 'positions-remain-fixed', + title: 'Results can be mixed', + fieldName: 'theres-a-stasis', + width: 'medium', + grow: false, + }); + controlGroupInputBuilder.addRangeSliderControl(controlGroupInput, { + dataViewId: 'an-object-set-in-motion', + title: 'The arbiter of time', + fieldName: 'unexpressed-emotion', + width: 'medium', + grow: false, + }); + controlGroupInputBuilder.addTimeSliderControl(controlGroupInput); + dashboardInput.controlGroupInput = controlGroupInput; const embeddableService: DashboardEmbeddableService = { getEmbeddableFactory: jest.fn(() => ({ @@ -42,8 +62,11 @@ describe('Migrate dashboard input', () => { // migration run should be true because the runEmbeddableFactoryMigrations mock above returns true. expect(result.anyMigrationRun).toBe(true); - expect(embeddableService.getEmbeddableFactory).toHaveBeenCalledTimes(4); // should be called 4 times for the panels, and 3 times for the controls + expect(embeddableService.getEmbeddableFactory).toHaveBeenCalledTimes(7); // should be called 4 times for the panels, and 3 times for the controls expect(embeddableService.getEmbeddableFactory).toHaveBeenCalledWith('superLens'); expect(embeddableService.getEmbeddableFactory).toHaveBeenCalledWith('ultraDiscover'); + expect(embeddableService.getEmbeddableFactory).toHaveBeenCalledWith('optionsListControl'); + expect(embeddableService.getEmbeddableFactory).toHaveBeenCalledWith('rangeSliderControl'); + expect(embeddableService.getEmbeddableFactory).toHaveBeenCalledWith('timeSlider'); }); }); diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.ts b/src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.ts index 70a6df30303dd..46e57588a2c95 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { ControlGroupInput } from '@kbn/controls-plugin/common'; import { EmbeddableFactoryNotFoundError, runEmbeddableFactoryMigrations, @@ -30,7 +31,28 @@ export const migrateDashboardInput = ( } = pluginServices.getServices(); let anyMigrationRun = false; if (!dashboardInput) return dashboardInput; + if (dashboardInput.controlGroupInput) { + /** + * If any Control Group migrations are required, we will need to start storing a Control Group Input version + * string in Dashboard Saved Objects and then running the whole Control Group input through the embeddable + * factory migrations here. + */ + // Migrate all of the Control children as well. + const migratedControls: ControlGroupInput['panels'] = {}; + + Object.entries(dashboardInput.controlGroupInput.panels).forEach(([id, panel]) => { + const factory = embeddable.getEmbeddableFactory(panel.type); + if (!factory) throw new EmbeddableFactoryNotFoundError(panel.type); + const { input: newInput, migrationRun: controlMigrationRun } = runEmbeddableFactoryMigrations( + panel.explicitInput, + factory + ); + if (controlMigrationRun) anyMigrationRun = true; + panel.explicitInput = newInput as DashboardPanelState['explicitInput']; + migratedControls[id] = panel; + }); + } const migratedPanels: DashboardContainerInput['panels'] = {}; for (const [id, panel] of Object.entries(dashboardInput.panels)) { // if the panel type is registered in the new embeddable system, we do not need to run migrations for it. diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/save_dashboard_state.ts b/src/plugins/dashboard/public/services/dashboard_content_management/lib/save_dashboard_state.ts index 94ebcd0702f2c..c69f7fa065a7b 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/lib/save_dashboard_state.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management/lib/save_dashboard_state.ts @@ -9,6 +9,12 @@ import { pick } from 'lodash'; import moment, { Moment } from 'moment'; +import { + controlGroupInputToRawControlGroupAttributes, + generateNewControlIds, + getDefaultControlGroupInput, + persistableControlGroupInputIsEqual, +} from '@kbn/controls-plugin/common'; import { extractSearchSourceReferences, RefreshInterval } from '@kbn/data-plugin/public'; import { isFilterPinned } from '@kbn/es-query'; @@ -23,10 +29,24 @@ import { DashboardContentManagementRequiredServices, SaveDashboardProps, SaveDashboardReturn, + SavedDashboardInput, } from '../types'; import { convertDashboardVersionToNumber } from './dashboard_versioning'; import { generateNewPanelIds } from '../../../../common/lib/dashboard_panel_converters'; +export const serializeControlGroupInput = ( + controlGroupInput: SavedDashboardInput['controlGroupInput'] +) => { + // only save to saved object if control group is not default + if ( + !controlGroupInput || + persistableControlGroupInputIsEqual(controlGroupInput, getDefaultControlGroupInput()) + ) { + return undefined; + } + return controlGroupInputToRawControlGroupAttributes(controlGroupInput); +}; + export const convertTimeToUTCString = (time?: string | Moment): undefined | string => { if (moment(time).isValid()) { return moment(time).utc().format('YYYY-MM-DDTHH:mm:ss.SSS[Z]'); @@ -48,7 +68,6 @@ type SaveDashboardStateProps = SaveDashboardProps & { }; export const saveDashboardState = async ({ - controlGroupReferences, data, embeddable, lastSavedId, @@ -81,10 +100,9 @@ export const saveDashboardState = async ({ syncCursor, syncTooltips, hidePanelTitles, - controlGroupInput, } = currentState; - let { panels } = currentState; + let { panels, controlGroupInput } = currentState; let prefixedPanelReferences = panelReferences; if (saveOptions.saveAsCopy) { const { panels: newPanels, references: newPanelReferences } = generateNewPanelIds( @@ -93,10 +111,7 @@ export const saveDashboardState = async ({ ); panels = newPanels; prefixedPanelReferences = newPanelReferences; - // - // do not need to generate new ids for controls. - // ControlGroup Component is keyed on dashboard id so changing dashboard id mounts new ControlGroup Component. - // + controlGroupInput = generateNewControlIds(controlGroupInput); } /** @@ -144,7 +159,7 @@ export const saveDashboardState = async ({ const rawDashboardAttributes: DashboardAttributes = { version: convertDashboardVersionToNumber(LATEST_DASHBOARD_CONTAINER_VERSION), - controlGroupInput, + controlGroupInput: serializeControlGroupInput(controlGroupInput), kibanaSavedObjectMeta: { searchSourceJSON }, description: description ?? '', refreshInterval, @@ -171,11 +186,7 @@ export const saveDashboardState = async ({ ? savedObjectsTagging.updateTagsReferences(dashboardReferences, tags) : dashboardReferences; - const allReferences = [ - ...references, - ...(prefixedPanelReferences ?? []), - ...(controlGroupReferences ?? []), - ]; + const allReferences = [...references, ...(prefixedPanelReferences ?? [])]; /** * Save the saved object using the content management diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/types.ts b/src/plugins/dashboard/public/services/dashboard_content_management/types.ts index 3caa5f73e65b2..ac8b921672e2d 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/types.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management/types.ts @@ -7,11 +7,11 @@ */ import type { Reference } from '@kbn/content-management-utils'; +import { PersistableControlGroupInput } from '@kbn/controls-plugin/common'; import { SavedObjectSaveOpts } from '@kbn/saved-objects-plugin/public'; -import { ControlGroupRuntimeState } from '@kbn/controls-plugin/public'; import { DashboardContainerInput } from '../../../common'; -import { DashboardAttributes, DashboardCrudTypes } from '../../../common/content_management'; +import { DashboardCrudTypes } from '../../../common/content_management'; import { DashboardStartDependencies } from '../../plugin'; import { DashboardBackupServiceType } from '../dashboard_backup/types'; import { DashboardDataService } from '../data/types'; @@ -64,17 +64,7 @@ export interface LoadDashboardFromSavedObjectProps { type DashboardResolveMeta = DashboardCrudTypes['GetOut']['meta']; export type SavedDashboardInput = DashboardContainerInput & { - /** - * Serialized control group state. - * Contains state loaded from dashboard saved object - */ - controlGroupInput?: DashboardAttributes['controlGroupInput'] | undefined; - /** - * Runtime control group state. - * Contains state passed from dashboard locator - * Use runtime state when building input for portable dashboards - */ - controlGroupState?: Partial; + controlGroupInput?: PersistableControlGroupInput; }; export interface LoadDashboardReturn { @@ -99,7 +89,6 @@ export interface LoadDashboardReturn { export type SavedDashboardSaveOpts = SavedObjectSaveOpts & { saveAsCopy?: boolean }; export interface SaveDashboardProps { - controlGroupReferences?: Reference[]; currentState: SavedDashboardInput; saveOptions: SavedDashboardSaveOpts; panelReferences?: Reference[]; diff --git a/src/plugins/embeddable/public/lib/containers/container.ts b/src/plugins/embeddable/public/lib/containers/container.ts index e4ce579104bb5..cac385dd2c86d 100644 --- a/src/plugins/embeddable/public/lib/containers/container.ts +++ b/src/plugins/embeddable/public/lib/containers/container.ts @@ -82,9 +82,6 @@ export abstract class Container< const init$ = this.getInput$().pipe( take(1), mergeMap(async (currentInput) => { - if (settings?.untilContainerInitialized) { - await settings.untilContainerInitialized(); - } const initPromise = this.initializeChildEmbeddables(currentInput, settings); if (awaitingInitialize) await initPromise; }) diff --git a/src/plugins/embeddable/public/lib/containers/i_container.ts b/src/plugins/embeddable/public/lib/containers/i_container.ts index 5ee9b0a250adc..53226e7d15146 100644 --- a/src/plugins/embeddable/public/lib/containers/i_container.ts +++ b/src/plugins/embeddable/public/lib/containers/i_container.ts @@ -37,8 +37,6 @@ export interface EmbeddableContainerSettings { * Initialise children in the order specified. If an ID does not match it will be skipped and if a child is not included it will be initialized in the default order after the list of provided IDs. */ childIdInitializeOrder?: string[]; - - untilContainerInitialized?: () => Promise; } export interface IContainer< diff --git a/src/plugins/embeddable/public/lib/embeddables/compatibility/embeddable_compatibility_utils.ts b/src/plugins/embeddable/public/lib/embeddables/compatibility/embeddable_compatibility_utils.ts index e34fc02acd6be..57cfe3350420a 100644 --- a/src/plugins/embeddable/public/lib/embeddables/compatibility/embeddable_compatibility_utils.ts +++ b/src/plugins/embeddable/public/lib/embeddables/compatibility/embeddable_compatibility_utils.ts @@ -51,11 +51,7 @@ export const embeddableInputToSubject = < subscription.add( embeddable .getInput$() - .pipe( - distinctUntilKeyChanged(key, (prev, current) => { - return deepEqual(prev, current); - }) - ) + .pipe(distinctUntilKeyChanged(key)) .subscribe(() => subject.next(embeddable.getInput()?.[key] as ValueType)) ); } diff --git a/src/plugins/embeddable/public/lib/embeddables/diff_embeddable_input.ts b/src/plugins/embeddable/public/lib/embeddables/diff_embeddable_input.ts index 79e7b5b99bc60..16b41ec9cc23c 100644 --- a/src/plugins/embeddable/public/lib/embeddables/diff_embeddable_input.ts +++ b/src/plugins/embeddable/public/lib/embeddables/diff_embeddable_input.ts @@ -58,19 +58,16 @@ export const genericEmbeddableInputIsEqual = ( const { title: currentTitle, hidePanelTitles: currentHidePanelTitles, - enhancements: currentEnhancements, ...current } = pick(currentInput as GenericEmbedableInputToCompare, genericInputKeysToCompare); const { title: lastTitle, hidePanelTitles: lastHidePanelTitles, - enhancements: lastEnhancements, ...last } = pick(lastInput as GenericEmbedableInputToCompare, genericInputKeysToCompare); if (currentTitle !== lastTitle) return false; if (Boolean(currentHidePanelTitles) !== Boolean(lastHidePanelTitles)) return false; - if (!fastIsEqual(currentEnhancements ?? {}, lastEnhancements ?? {})) return false; if (!fastIsEqual(current, last)) return false; return true; }; diff --git a/test/functional/apps/dashboard_elements/controls/common/control_group_apply_button.ts b/test/functional/apps/dashboard_elements/controls/common/control_group_apply_button.ts index f0e4cce0c8adb..683d6a6e7cc22 100644 --- a/test/functional/apps/dashboard_elements/controls/common/control_group_apply_button.ts +++ b/test/functional/apps/dashboard_elements/controls/common/control_group_apply_button.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { OPTIONS_LIST_CONTROL, RANGE_SLIDER_CONTROL } from '@kbn/controls-plugin/common'; import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../../ftr_provider_context'; @@ -13,25 +14,77 @@ import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const pieChart = getService('pieChart'); const elasticChart = getService('elasticChart'); + const testSubjects = getService('testSubjects'); + const dashboardAddPanel = getService('dashboardAddPanel'); - const { dashboard, header, dashboardControls } = getPageObjects([ + const { dashboard, header, dashboardControls, timePicker } = getPageObjects([ 'dashboardControls', + 'timePicker', 'dashboard', 'header', ]); describe('Dashboard control group apply button', () => { - const optionsListId = '41827e70-5285-4d44-8375-4c498449b9a7'; - const rangeSliderId = '515e7b9f-4f1b-4a06-beec-763810e4951a'; + let controlIds: string[]; before(async () => { await dashboard.navigateToApp(); - await dashboard.loadSavedDashboard('Test Control Group Apply Button'); - await dashboard.switchToEditMode(); + await dashboard.gotoDashboardLandingPage(); + await dashboard.clickNewDashboard(); + await timePicker.setDefaultDataRange(); + await elasticChart.setNewChartUiDebugFlag(); + await dashboardAddPanel.addVisualization('Rendering-Test:-animal-sounds-pie'); + + // save the dashboard before adding controls + await dashboard.saveDashboard('Test Control Group Apply Button', { + exitFromEditMode: false, + saveAsNew: true, + }); + await header.waitUntilLoadingHasFinished(); + await dashboard.waitForRenderComplete(); + await dashboard.expectMissingUnsavedChangesBadge(); + + // populate an initial set of controls and get their ids. + await dashboardControls.createControl({ + controlType: OPTIONS_LIST_CONTROL, + dataViewTitle: 'animals-*', + fieldName: 'animal.keyword', + title: 'Animal', + }); + await dashboardControls.createControl({ + controlType: RANGE_SLIDER_CONTROL, + dataViewTitle: 'animals-*', + fieldName: 'weightLbs', + title: 'Animal Name', + }); + await dashboardControls.createTimeSliderControl(); + + // wait for all controls to finish loading before saving + controlIds = await dashboardControls.getAllControlIds(); + await dashboardControls.optionsListWaitForLoading(controlIds[0]); + await dashboardControls.rangeSliderWaitForLoading(controlIds[1]); + + // re-save the dashboard + await dashboard.clickQuickSave(); + await header.waitUntilLoadingHasFinished(); + await dashboard.waitForRenderComplete(); + await dashboard.expectMissingUnsavedChangesBadge(); + }); + + it('able to set apply button setting', async () => { + await dashboardControls.updateShowApplyButtonSetting(true); + await testSubjects.existOrFail('controlGroup--applyFiltersButton'); + await dashboard.expectUnsavedChangesBadge(); + + await dashboard.clickQuickSave(); + await header.waitUntilLoadingHasFinished(); + await dashboard.expectMissingUnsavedChangesBadge(); }); it('renabling auto-apply forces filters to be published', async () => { + const optionsListId = controlIds[0]; + await dashboardControls.verifyApplyButtonEnabled(false); await dashboardControls.optionsListOpenPopover(optionsListId); await dashboardControls.optionsListPopoverSelectOption('cat'); await dashboardControls.optionsListEnsurePopoverIsClosed(optionsListId); @@ -48,7 +101,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); describe('options list selections', () => { + let optionsListId: string; + + before(async () => { + optionsListId = controlIds[0]; + }); + it('making selection enables apply button', async () => { + await dashboardControls.verifyApplyButtonEnabled(false); await dashboardControls.optionsListOpenPopover(optionsListId); await dashboardControls.optionsListPopoverSelectOption('cat'); await dashboardControls.optionsListEnsurePopoverIsClosed(optionsListId); @@ -57,6 +117,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('waits to apply filters until button is pressed', async () => { + await dashboard.expectMissingUnsavedChangesBadge(); expect(await pieChart.getPieSliceCount()).to.be(5); await dashboardControls.clickApplyButton(); @@ -78,19 +139,27 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await header.waitUntilLoadingHasFinished(); await dashboard.waitForRenderComplete(); - await dashboard.expectMissingUnsavedChangesBadge(); expect(await pieChart.getPieSliceCount()).to.be(5); + await dashboardControls.verifyApplyButtonEnabled(false); expect(await dashboardControls.optionsListGetSelectionsString(optionsListId)).to.be('Any'); }); }); describe('range slider selections', () => { + let rangeSliderId: string; + + before(async () => { + rangeSliderId = controlIds[1]; + }); + it('making selection enables apply button', async () => { + await dashboardControls.verifyApplyButtonEnabled(false); await dashboardControls.rangeSliderSetUpperBound(rangeSliderId, '30'); await dashboardControls.verifyApplyButtonEnabled(); }); it('waits to apply filters until apply button is pressed', async () => { + await dashboard.expectMissingUnsavedChangesBadge(); expect(await pieChart.getPieSliceCount()).to.be(5); await dashboardControls.clickApplyButton(); @@ -111,8 +180,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await header.waitUntilLoadingHasFinished(); await dashboard.waitForRenderComplete(); - await dashboard.expectMissingUnsavedChangesBadge(); expect(await pieChart.getPieSliceCount()).to.be(5); + await dashboardControls.verifyApplyButtonEnabled(false); expect( await dashboardControls.rangeSliderGetLowerBoundAttribute(rangeSliderId, 'value') ).to.be(''); @@ -130,6 +199,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('making selection enables apply button', async () => { + await dashboardControls.verifyApplyButtonEnabled(false); await dashboardControls.gotoNextTimeSlice(); await dashboardControls.gotoNextTimeSlice(); // go to an empty timeslice await header.waitUntilLoadingHasFinished(); @@ -137,6 +207,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('waits to apply timeslice until apply button is pressed', async () => { + await dashboard.expectMissingUnsavedChangesBadge(); expect(await pieChart.getPieSliceCount()).to.be(5); await dashboardControls.clickApplyButton(); @@ -155,8 +226,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await header.waitUntilLoadingHasFinished(); await dashboard.waitForRenderComplete(); - await dashboard.expectMissingUnsavedChangesBadge(); expect(await pieChart.getPieSliceCount()).to.be(5); + await dashboardControls.verifyApplyButtonEnabled(false); const valueNow = await dashboardControls.getTimeSliceFromTimeSlider(); expect(valueNow).to.equal(valueBefore); }); diff --git a/test/functional/apps/dashboard_elements/controls/common/multiple_data_views.ts b/test/functional/apps/dashboard_elements/controls/common/multiple_data_views.ts index f20052add7243..5a07e60d45695 100644 --- a/test/functional/apps/dashboard_elements/controls/common/multiple_data_views.ts +++ b/test/functional/apps/dashboard_elements/controls/common/multiple_data_views.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { OPTIONS_LIST_CONTROL, RANGE_SLIDER_CONTROL } from '@kbn/controls-plugin/common'; import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../../ftr_provider_context'; @@ -16,29 +17,17 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); const filterBar = getService('filterBar'); const testSubjects = getService('testSubjects'); - const { dashboard, dashboardControls } = getPageObjects([ + const dashboardAddPanel = getService('dashboardAddPanel'); + const { common, dashboard, dashboardControls } = getPageObjects([ 'dashboardControls', 'dashboard', 'console', + 'common', 'header', ]); describe('Dashboard control group with multiple data views', () => { - // Controls from flights data view - const carrierControlId = '265b6a28-9ccb-44ae-83c9-3d7a7cac1961'; - const ticketPriceControlId = 'ed2b93e2-da37-482b-ae43-586a41cc2399'; - // Controls from logstash-* data view - const osControlId = '5e1b146b-8a8b-4117-9218-c4aeaee7bc9a'; - const bytesControlId = 'c4760951-e793-45d5-a6b7-c72c145af7f9'; - - async function waitForAllConrolsLoading() { - await Promise.all([ - dashboardControls.optionsListWaitForLoading(carrierControlId), - dashboardControls.rangeSliderWaitForLoading(ticketPriceControlId), - dashboardControls.optionsListWaitForLoading(osControlId), - dashboardControls.rangeSliderWaitForLoading(bytesControlId), - ]); - } + let controlIds: string[]; before(async () => { await security.testUser.setRoles(['kibana_admin', 'kibana_sample_admin']); @@ -50,12 +39,50 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.importExport.load( 'test/functional/fixtures/kbn_archiver/kibana_sample_data_flights_index_pattern' ); - await kibanaServer.importExport.load( - 'test/functional/fixtures/kbn_archiver/dashboard/current/multi_data_view_kibana' - ); await kibanaServer.uiSettings.replace({ defaultIndex: '0bf35f60-3dc9-11e8-8660-4d65aa086b3c', + 'courier:ignoreFilterIfFieldNotInIndex': true, + }); + + await common.setTime({ + from: 'Apr 10, 2018 @ 00:00:00.000', + to: 'Nov 15, 2018 @ 00:00:00.000', + }); + + await dashboard.navigateToApp(); + await dashboard.clickNewDashboard(); + + await dashboardControls.createControl({ + controlType: OPTIONS_LIST_CONTROL, + dataViewTitle: 'kibana_sample_data_flights', + fieldName: 'Carrier', + title: 'Carrier', + }); + + await dashboardControls.createControl({ + controlType: RANGE_SLIDER_CONTROL, + dataViewTitle: 'kibana_sample_data_flights', + fieldName: 'AvgTicketPrice', + title: 'Average Ticket Price', }); + + await dashboardControls.createControl({ + controlType: OPTIONS_LIST_CONTROL, + dataViewTitle: 'logstash-*', + fieldName: 'machine.os.raw', + title: 'Operating System', + }); + + await dashboardControls.createControl({ + controlType: RANGE_SLIDER_CONTROL, + dataViewTitle: 'logstash-*', + fieldName: 'bytes', + title: 'Bytes', + }); + + await dashboardAddPanel.addSavedSearch('logstash hits'); + + controlIds = await dashboardControls.getAllControlIds(); }); after(async () => { @@ -66,169 +93,96 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.importExport.unload( 'test/functional/fixtures/kbn_archiver/kibana_sample_data_flights_index_pattern' ); - await kibanaServer.importExport.unload( - 'test/functional/fixtures/kbn_archiver/dashboard/current/multi_data_view_kibana' - ); await security.testUser.restoreDefaults(); + await kibanaServer.uiSettings.unset('courier:ignoreFilterIfFieldNotInIndex'); await kibanaServer.uiSettings.unset('defaultIndex'); }); - describe('courier:ignoreFilterIfFieldNotInIndex enabled', () => { - before(async () => { - await kibanaServer.uiSettings.replace({ - 'courier:ignoreFilterIfFieldNotInIndex': true, - }); + it('ignores global filters on controls using a data view without the filter field', async () => { + await filterBar.addFilter({ field: 'Carrier', operation: 'exists' }); - await dashboard.navigateToApp(); - await dashboard.loadSavedDashboard('Test Control Group With Multiple Data Views'); - }); + await dashboardControls.optionsListOpenPopover(controlIds[0]); + expect(await dashboardControls.optionsListGetCardinalityValue()).to.be('4'); + await dashboardControls.optionsListEnsurePopoverIsClosed(controlIds[0]); - after(async () => { - await kibanaServer.uiSettings.unset('courier:ignoreFilterIfFieldNotInIndex'); - }); + await dashboardControls.validateRange('placeholder', controlIds[1], '100', '1200'); - describe('global filters', () => { - before(async () => { - await filterBar.addFilter({ - field: 'Carrier', - operation: 'is', - value: 'Kibana Airlines', - }); - await waitForAllConrolsLoading(); - }); - - after(async () => { - await dashboard.clickDiscardChanges(); - }); - - it('applies global filters to controls with data view of filter field', async () => { - await dashboardControls.optionsListOpenPopover(carrierControlId); - expect(await dashboardControls.optionsListGetCardinalityValue()).to.be('1'); - await dashboardControls.optionsListEnsurePopoverIsClosed(carrierControlId); - - await dashboardControls.validateRange('placeholder', ticketPriceControlId, '100', '1196'); - }); - - it('ignores global filters to controls without data view of filter field', async () => { - await dashboardControls.optionsListOpenPopover(osControlId); - expect(await dashboardControls.optionsListGetCardinalityValue()).to.be('5'); - await dashboardControls.optionsListEnsurePopoverIsClosed(osControlId); - - await dashboardControls.validateRange('placeholder', bytesControlId, '0', '19979'); - }); - }); + await dashboardControls.optionsListOpenPopover(controlIds[2]); + expect(await dashboardControls.optionsListGetCardinalityValue()).to.be('5'); + await dashboardControls.optionsListEnsurePopoverIsClosed(controlIds[2]); - describe('control filters', () => { - before(async () => { - await dashboardControls.optionsListOpenPopover(carrierControlId); - await dashboardControls.optionsListPopoverSelectOption('Kibana Airlines'); - await dashboardControls.optionsListEnsurePopoverIsClosed(carrierControlId); - await waitForAllConrolsLoading(); - }); - - after(async () => { - await dashboard.clickDiscardChanges(); - }); - - it('applies control filters to controls with data view of control filter', async () => { - await dashboardControls.validateRange('placeholder', ticketPriceControlId, '100', '1196'); - }); - - it('ignores control filters on controls without data view of control filter', async () => { - await dashboardControls.optionsListOpenPopover(osControlId); - expect(await dashboardControls.optionsListGetCardinalityValue()).to.be('5'); - await dashboardControls.optionsListEnsurePopoverIsClosed(osControlId); - - await dashboardControls.validateRange('placeholder', bytesControlId, '0', '19979'); - }); - - it('ignores control filters on panels without data view of control filter', async () => { - const logstashSavedSearchPanel = await testSubjects.find('embeddedSavedSearchDocTable'); - expect( - await ( - await logstashSavedSearchPanel.findByCssSelector('[data-document-number]') - ).getAttribute('data-document-number') - ).to.not.be('0'); - }); - }); + await dashboardControls.validateRange('placeholder', controlIds[3], '0', '19979'); }); - describe('courier:ignoreFilterIfFieldNotInIndex disabled', () => { - before(async () => { - await kibanaServer.uiSettings.replace({ - 'courier:ignoreFilterIfFieldNotInIndex': false, - }); + it('ignores controls on other controls and panels using a data view without the control field by default', async () => { + await filterBar.removeFilter('Carrier'); + await dashboardControls.optionsListOpenPopover(controlIds[0]); + await dashboardControls.optionsListPopoverSelectOption('Kibana Airlines'); + await dashboardControls.optionsListEnsurePopoverIsClosed(controlIds[0]); - await dashboard.navigateToApp(); - await dashboard.loadSavedDashboard('Test Control Group With Multiple Data Views'); - }); + await dashboardControls.validateRange('placeholder', controlIds[1], '100', '1196'); - after(async () => { - await kibanaServer.uiSettings.unset('courier:ignoreFilterIfFieldNotInIndex'); - }); + await dashboardControls.optionsListOpenPopover(controlIds[2]); + expect(await dashboardControls.optionsListGetCardinalityValue()).to.be('5'); + await dashboardControls.optionsListEnsurePopoverIsClosed(controlIds[2]); - describe('global filters', () => { - before(async () => { - await filterBar.addFilter({ - field: 'Carrier', - operation: 'is', - value: 'Kibana Airlines', - }); - await waitForAllConrolsLoading(); - }); - - after(async () => { - await dashboard.clickDiscardChanges(); - }); - - it('applies global filters to controls without data view of filter field', async () => { - await dashboardControls.optionsListOpenPopover(osControlId); - expect(await dashboardControls.optionsListGetCardinalityValue()).to.be('0'); - await dashboardControls.optionsListEnsurePopoverIsClosed(osControlId); - - await dashboardControls.validateRange( - 'placeholder', - bytesControlId, - '-Infinity', - 'Infinity' - ); - }); - }); + await dashboardControls.validateRange('placeholder', controlIds[3], '0', '19979'); - describe('control filters', () => { - before(async () => { - await dashboardControls.optionsListOpenPopover(carrierControlId); - await dashboardControls.optionsListPopoverSelectOption('Kibana Airlines'); - await dashboardControls.optionsListEnsurePopoverIsClosed(carrierControlId); - await waitForAllConrolsLoading(); - }); - - after(async () => { - await dashboard.clickDiscardChanges(); - }); - - it('applies control filters on controls without data view of control filter', async () => { - await dashboardControls.optionsListOpenPopover(osControlId); - expect(await dashboardControls.optionsListGetCardinalityValue()).to.be('0'); - await dashboardControls.optionsListEnsurePopoverIsClosed(osControlId); - - await dashboardControls.validateRange( - 'placeholder', - bytesControlId, - '-Infinity', - 'Infinity' - ); - }); - - it('applies control filters on panels without data view of control filter', async () => { - const logstashSavedSearchPanel = await testSubjects.find('embeddedSavedSearchDocTable'); - expect( - await ( - await logstashSavedSearchPanel.findByCssSelector('[data-document-number]') - ).getAttribute('data-document-number') - ).to.be('0'); - }); - }); + const logstashSavedSearchPanel = await testSubjects.find('embeddedSavedSearchDocTable'); + expect( + await ( + await logstashSavedSearchPanel.findByCssSelector('[data-document-number]') + ).getAttribute('data-document-number') + ).to.not.be('0'); + }); + + it('applies global filters on controls using data view a without the filter field', async () => { + await kibanaServer.uiSettings.update({ 'courier:ignoreFilterIfFieldNotInIndex': false }); + await common.navigateToApp('dashboard'); + await testSubjects.click('edit-unsaved-New-Dashboard'); + await filterBar.addFilter({ field: 'Carrier', operation: 'exists' }); + + await Promise.all([ + dashboardControls.optionsListWaitForLoading(controlIds[0]), + dashboardControls.rangeSliderWaitForLoading(controlIds[1]), + dashboardControls.optionsListWaitForLoading(controlIds[2]), + dashboardControls.rangeSliderWaitForLoading(controlIds[3]), + ]); + + await dashboardControls.clearControlSelections(controlIds[0]); + await dashboardControls.optionsListOpenPopover(controlIds[0]); + expect(await dashboardControls.optionsListGetCardinalityValue()).to.be('4'); + await dashboardControls.optionsListEnsurePopoverIsClosed(controlIds[0]); + + await dashboardControls.validateRange('placeholder', controlIds[1], '100', '1200'); + + await dashboardControls.optionsListOpenPopover(controlIds[2]); + expect(await dashboardControls.optionsListGetCardinalityValue()).to.be('0'); + await dashboardControls.optionsListEnsurePopoverIsClosed(controlIds[2]); + + await dashboardControls.validateRange('placeholder', controlIds[3], '0', '0'); + }); + + it('applies global filters on controls using a data view without the filter field', async () => { + await filterBar.removeFilter('Carrier'); + await dashboardControls.optionsListOpenPopover(controlIds[0]); + await dashboardControls.optionsListPopoverSelectOption('Kibana Airlines'); + await dashboardControls.optionsListEnsurePopoverIsClosed(controlIds[0]); + + await dashboardControls.validateRange('placeholder', controlIds[1], '100', '1196'); + + await dashboardControls.optionsListOpenPopover(controlIds[2]); + expect(await dashboardControls.optionsListGetCardinalityValue()).to.be('0'); + await dashboardControls.optionsListEnsurePopoverIsClosed(controlIds[2]); + + await dashboardControls.validateRange('placeholder', controlIds[3], '0', '0'); + + const logstashSavedSearchPanel = await testSubjects.find('embeddedSavedSearchDocTable'); + expect( + await ( + await logstashSavedSearchPanel.findByCssSelector('[data-document-number]') + ).getAttribute('data-document-number') + ).to.be('0'); }); }); } diff --git a/test/functional/apps/dashboard_elements/controls/common/replace_controls.ts b/test/functional/apps/dashboard_elements/controls/common/replace_controls.ts index 5d0199fc248e4..22980eb6423a2 100644 --- a/test/functional/apps/dashboard_elements/controls/common/replace_controls.ts +++ b/test/functional/apps/dashboard_elements/controls/common/replace_controls.ts @@ -35,17 +35,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const replaceWithOptionsList = async (controlId: string, field: string) => { await changeFieldType(controlId, field, OPTIONS_LIST_CONTROL); - const newControlId: string = (await dashboardControls.getAllControlIds())[0]; - await testSubjects.waitForEnabled(`optionsList-control-${newControlId}`); - await dashboardControls.verifyControlType(newControlId, 'optionsList-control'); + await testSubjects.waitForEnabled(`optionsList-control-${controlId}`); + await dashboardControls.verifyControlType(controlId, 'optionsList-control'); }; const replaceWithRangeSlider = async (controlId: string, field: string) => { await changeFieldType(controlId, field, RANGE_SLIDER_CONTROL); await retry.try(async () => { - const newControlId: string = (await dashboardControls.getAllControlIds())[0]; - await dashboardControls.rangeSliderWaitForLoading(newControlId); - await dashboardControls.verifyControlType(newControlId, 'range-slider-control'); + await dashboardControls.rangeSliderWaitForLoading(controlId); + await dashboardControls.verifyControlType(controlId, 'range-slider-control'); }); }; @@ -70,6 +68,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('Replace options list', () => { beforeEach(async () => { + await dashboardControls.clearAllControls(); await dashboardControls.createControl({ controlType: OPTIONS_LIST_CONTROL, dataViewTitle: 'animals-*', @@ -79,7 +78,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); afterEach(async () => { - await dashboardControls.clearAllControls(); + await dashboard.clearUnsavedChanges(); }); it('with range slider - default title', async () => { @@ -101,6 +100,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('Replace range slider', () => { beforeEach(async () => { + await dashboardControls.clearAllControls(); await dashboardControls.createControl({ controlType: RANGE_SLIDER_CONTROL, dataViewTitle: 'animals-*', @@ -111,7 +111,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); afterEach(async () => { - await dashboardControls.clearAllControls(); + await dashboard.clearUnsavedChanges(); }); it('with options list - default title', async () => { diff --git a/test/functional/apps/dashboard_elements/controls/options_list/options_list_suggestions.ts b/test/functional/apps/dashboard_elements/controls/options_list/options_list_suggestions.ts index 87d754b053301..220b9819f4466 100644 --- a/test/functional/apps/dashboard_elements/controls/options_list/options_list_suggestions.ts +++ b/test/functional/apps/dashboard_elements/controls/options_list/options_list_suggestions.ts @@ -17,7 +17,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const { dashboardControls, dashboard, header } = getPageObjects([ 'dashboardControls', + 'timePicker', 'dashboard', + 'settings', + 'console', + 'common', 'header', ]); @@ -48,7 +52,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async () => { await dashboardControls.optionsListEnsurePopoverIsClosed(controlId); - await dashboard.clickDiscardChanges(); }); it('sort alphabetically - descending', async () => { @@ -130,6 +133,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { for (let i = 0; i < sortedSuggestions.length - 1; i++) { expect(sortedSuggestions[i]).to.be.lessThan(sortedSuggestions[i + 1]); } + + // revert to the old field name to keep state consistent for other tests + await dashboardControls.editExistingControl(controlId); + await dashboardControls.controlsEditorSetfield('sound.keyword'); + await dashboardControls.optionsListSetAdditionalSettings({ searchTechnique: 'prefix' }); + await dashboardControls.controlEditorSave(); }); }); diff --git a/test/functional/apps/dashboard_elements/controls/options_list/options_list_validation.ts b/test/functional/apps/dashboard_elements/controls/options_list/options_list_validation.ts index bff1e069b2ff0..fa4322963381c 100644 --- a/test/functional/apps/dashboard_elements/controls/options_list/options_list_validation.ts +++ b/test/functional/apps/dashboard_elements/controls/options_list/options_list_validation.ts @@ -9,6 +9,7 @@ import { pick } from 'lodash'; import expect from '@kbn/expect'; +import { OPTIONS_LIST_CONTROL } from '@kbn/controls-plugin/common'; import { FtrProviderContext } from '../../../../ftr_provider_context'; import { OPTIONS_LIST_ANIMAL_SOUND_SUGGESTIONS } from '../../../../page_objects/dashboard_page_controls'; @@ -17,6 +18,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const queryBar = getService('queryBar'); const pieChart = getService('pieChart'); const filterBar = getService('filterBar'); + const dashboardAddPanel = getService('dashboardAddPanel'); + const dashboardPanelActions = getService('dashboardPanelActions'); const { dashboardControls, dashboard, header } = getPageObjects([ 'dashboardControls', @@ -29,18 +32,41 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ]); describe('Dashboard options list validation', () => { - const controlId = 'cd881630-fd28-4e9c-aec5-ae9711d48369'; + let controlId: string; before(async () => { - await dashboard.loadSavedDashboard('Test Options List Validation'); await dashboard.ensureDashboardIsInEditMode(); + await dashboardControls.createControl({ + controlType: OPTIONS_LIST_CONTROL, + dataViewTitle: 'animals-*', + fieldName: 'sound.keyword', + title: 'Animal Sounds', + }); + controlId = (await dashboardControls.getAllControlIds())[0]; + await dashboardAddPanel.addVisualization('Rendering-Test:-animal-sounds-pie'); + await dashboard.clickQuickSave(); + await header.waitUntilLoadingHasFinished(); + }); + + after(async () => { + await filterBar.removeAllFilters(); + await dashboardControls.deleteAllControls(); + await dashboardPanelActions.removePanelByTitle('Rendering Test: animal sounds pie'); + await dashboard.clickQuickSave(); }); describe('Options List dashboard validation', () => { + before(async () => { + await dashboardControls.optionsListOpenPopover(controlId); + await dashboardControls.optionsListPopoverSelectOption('meow'); + await dashboardControls.optionsListPopoverSelectOption('bark'); + await dashboardControls.optionsListEnsurePopoverIsClosed(controlId); + }); + after(async () => { - // Instead of reset, filter must be manually deleted to avoid - // https://github.com/elastic/kibana/issues/191675 + await dashboardControls.clearControlSelections(controlId); await filterBar.removeAllFilters(); + await queryBar.clickQuerySubmitButton(); }); it('Can mark selections invalid with Query', async () => { @@ -92,13 +118,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('Options List dashboard no validation', () => { before(async () => { + await dashboardControls.optionsListOpenPopover(controlId); + await dashboardControls.optionsListPopoverSelectOption('meow'); + await dashboardControls.optionsListPopoverSelectOption('bark'); + await dashboardControls.optionsListEnsurePopoverIsClosed(controlId); await dashboardControls.updateValidationSetting(false); }); - after(async () => { - await dashboard.clickDiscardChanges(); - }); - it('Does not mark selections invalid with Query', async () => { await queryBar.setQuery('NOT animal.keyword : "dog" '); await queryBar.submitQuery(); diff --git a/test/functional/fixtures/kbn_archiver/dashboard/current/kibana.json b/test/functional/fixtures/kbn_archiver/dashboard/current/kibana.json index c4c2b4ab2d025..a89dcf714dfc3 100644 --- a/test/functional/fixtures/kbn_archiver/dashboard/current/kibana.json +++ b/test/functional/fixtures/kbn_archiver/dashboard/current/kibana.json @@ -3225,108 +3225,3 @@ "coreMigrationVersion": "8.8.0", "typeMigrationVersion": "10.2.0" } - -{ - "id": "55bc0b4b-a50f-46bf-b154-dd156067eea5", - "type": "dashboard", - "namespaces": [ - "default" - ], - "updated_at": "2024-08-26T13:30:47.442Z", - "created_at": "2024-08-26T13:29:23.580Z", - "version": "WzEwNiwxXQ==", - "attributes": { - "version": 2, - "controlGroupInput": { - "chainingSystem": "HIERARCHICAL", - "controlStyle": "oneLine", - "showApplySelections": true, - "ignoreParentSettingsJSON": "{\"ignoreFilters\":false,\"ignoreQuery\":false,\"ignoreTimerange\":false,\"ignoreValidations\":false}", - "panelsJSON": "{\"41827e70-5285-4d44-8375-4c498449b9a7\":{\"grow\":true,\"order\":0,\"type\":\"optionsListControl\",\"width\":\"medium\",\"explicitInput\":{\"dataViewId\":\"a0f483a0-3dc9-11e8-8660-4d65aa086b3c\",\"fieldName\":\"animal.keyword\",\"searchTechnique\":\"prefix\",\"selectedOptions\":[],\"sort\":{\"by\":\"_count\",\"direction\":\"desc\"}}},\"515e7b9f-4f1b-4a06-beec-763810e4951a\":{\"grow\":true,\"order\":1,\"type\":\"rangeSliderControl\",\"width\":\"medium\",\"explicitInput\":{\"dataViewId\":\"a0f483a0-3dc9-11e8-8660-4d65aa086b3c\",\"fieldName\":\"weightLbs\",\"step\":1}},\"b33b103a-84e2-4c2f-b4bd-be143dbd7e8a\":{\"grow\":true,\"order\":2,\"type\":\"timeSlider\",\"width\":\"large\",\"explicitInput\":{}}}" - }, - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" - }, - "description": "", - "refreshInterval": { - "pause": true, - "value": 60000 - }, - "timeRestore": true, - "optionsJSON": "{\"useMargins\":true,\"syncColors\":false,\"syncCursor\":true,\"syncTooltips\":false,\"hidePanelTitles\":false}", - "panelsJSON": "[{\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"ffc13252-56b4-4e3f-847e-61373fa0be86\"},\"panelIndex\":\"ffc13252-56b4-4e3f-847e-61373fa0be86\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_ffc13252-56b4-4e3f-847e-61373fa0be86\"}]", - "timeFrom": "2018-01-01T00:00:00.000Z", - "title": "Test Control Group Apply Button", - "timeTo": "2018-04-13T00:00:00.000Z" - }, - "references": [ - { - "name": "ffc13252-56b4-4e3f-847e-61373fa0be86:panel_ffc13252-56b4-4e3f-847e-61373fa0be86", - "type": "visualization", - "id": "50643b60-3dd3-11e8-b2b9-5d5dc1715159" - }, - { - "name": "controlGroup_41827e70-5285-4d44-8375-4c498449b9a7:optionsListControlDataView", - "type": "index-pattern", - "id": "a0f483a0-3dc9-11e8-8660-4d65aa086b3c" - }, - { - "name": "controlGroup_515e7b9f-4f1b-4a06-beec-763810e4951a:rangeSliderControlDataView", - "type": "index-pattern", - "id": "a0f483a0-3dc9-11e8-8660-4d65aa086b3c" - } - ], - "managed": false, - "coreMigrationVersion": "8.8.0", - "typeMigrationVersion": "10.2.0" -} - -{ - "id": "0b61857d-b7d3-4b4b-aa6b-773808361cd6", - "type": "dashboard", - "namespaces": [ - "default" - ], - "updated_at": "2024-08-26T15:23:33.053Z", - "created_at": "2024-08-26T15:22:39.194Z", - "version": "WzE1MTksMV0=", - "attributes": { - "version": 2, - "controlGroupInput": { - "chainingSystem": "HIERARCHICAL", - "controlStyle": "oneLine", - "showApplySelections": false, - "ignoreParentSettingsJSON": "{\"ignoreFilters\":false,\"ignoreQuery\":false,\"ignoreTimerange\":false,\"ignoreValidations\":false}", - "panelsJSON": "{\"cd881630-fd28-4e9c-aec5-ae9711d48369\":{\"grow\":true,\"order\":0,\"type\":\"optionsListControl\",\"width\":\"medium\",\"explicitInput\":{\"dataViewId\":\"a0f483a0-3dc9-11e8-8660-4d65aa086b3c\",\"fieldName\":\"sound.keyword\",\"searchTechnique\":\"prefix\",\"selectedOptions\":[\"meow\",\"bark\"],\"sort\":{\"by\":\"_count\",\"direction\":\"desc\"}}}}" - }, - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" - }, - "description": "", - "refreshInterval": { - "pause": true, - "value": 60000 - }, - "timeRestore": true, - "optionsJSON": "{\"useMargins\":true,\"syncColors\":false,\"syncCursor\":true,\"syncTooltips\":false,\"hidePanelTitles\":false}", - "panelsJSON": "[{\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"12415efc-008a-4f02-bad4-5c1f0d9ba1c6\"},\"panelIndex\":\"12415efc-008a-4f02-bad4-5c1f0d9ba1c6\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_12415efc-008a-4f02-bad4-5c1f0d9ba1c6\"}]", - "timeFrom": "2018-01-01T00:00:00.000Z", - "title": "Test Options List Validation", - "timeTo": "2018-04-13T00:00:00.000Z" - }, - "references": [ - { - "name": "12415efc-008a-4f02-bad4-5c1f0d9ba1c6:panel_12415efc-008a-4f02-bad4-5c1f0d9ba1c6", - "type": "visualization", - "id": "50643b60-3dd3-11e8-b2b9-5d5dc1715159" - }, - { - "name": "controlGroup_cd881630-fd28-4e9c-aec5-ae9711d48369:optionsListControlDataView", - "type": "index-pattern", - "id": "a0f483a0-3dc9-11e8-8660-4d65aa086b3c" - } - ], - "managed": false, - "coreMigrationVersion": "8.8.0", - "typeMigrationVersion": "10.2.0" -} \ No newline at end of file diff --git a/test/functional/fixtures/kbn_archiver/dashboard/current/multi_data_view_kibana.json b/test/functional/fixtures/kbn_archiver/dashboard/current/multi_data_view_kibana.json deleted file mode 100644 index 7a5de78d372aa..0000000000000 --- a/test/functional/fixtures/kbn_archiver/dashboard/current/multi_data_view_kibana.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "id": "2af8906f-143b-4152-9f74-4994fb9c7b3e", - "type": "dashboard", - "namespaces": [ - "default" - ], - "updated_at": "2024-08-27T16:43:33.847Z", - "created_at": "2024-08-27T16:43:33.847Z", - "version": "WzIwNSwxXQ==", - "attributes": { - "version": 2, - "controlGroupInput": { - "chainingSystem": "HIERARCHICAL", - "controlStyle": "oneLine", - "showApplySelections": false, - "ignoreParentSettingsJSON": "{\"ignoreFilters\":false,\"ignoreQuery\":false,\"ignoreTimerange\":false,\"ignoreValidations\":false}", - "panelsJSON": "{\"265b6a28-9ccb-44ae-83c9-3d7a7cac1961\":{\"grow\":true,\"order\":0,\"type\":\"optionsListControl\",\"width\":\"medium\",\"explicitInput\":{\"dataViewId\":\"d3d7af60-4c81-11e8-b3d7-01146121b73d\",\"fieldName\":\"Carrier\",\"searchTechnique\":\"prefix\",\"selectedOptions\":[],\"sort\":{\"by\":\"_count\",\"direction\":\"desc\"}}},\"ed2b93e2-da37-482b-ae43-586a41cc2399\":{\"grow\":true,\"order\":1,\"type\":\"rangeSliderControl\",\"width\":\"medium\",\"explicitInput\":{\"dataViewId\":\"d3d7af60-4c81-11e8-b3d7-01146121b73d\",\"fieldName\":\"AvgTicketPrice\",\"title\":\"Average Ticket Price\",\"step\":1}},\"5e1b146b-8a8b-4117-9218-c4aeaee7bc9a\":{\"grow\":true,\"order\":2,\"type\":\"optionsListControl\",\"width\":\"medium\",\"explicitInput\":{\"dataViewId\":\"0bf35f60-3dc9-11e8-8660-4d65aa086b3c\",\"fieldName\":\"machine.os.raw\",\"title\":\"Operating System\",\"searchTechnique\":\"prefix\",\"selectedOptions\":[],\"sort\":{\"by\":\"_count\",\"direction\":\"desc\"}}},\"c4760951-e793-45d5-a6b7-c72c145af7f9\":{\"grow\":true,\"order\":3,\"type\":\"rangeSliderControl\",\"width\":\"medium\",\"explicitInput\":{\"dataViewId\":\"0bf35f60-3dc9-11e8-8660-4d65aa086b3c\",\"fieldName\":\"bytes\",\"title\":\"Bytes\",\"step\":1}}}" - }, - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" - }, - "description": "", - "refreshInterval": { - "pause": true, - "value": 60000 - }, - "timeRestore": true, - "optionsJSON": "{\"useMargins\":true,\"syncColors\":false,\"syncCursor\":true,\"syncTooltips\":false,\"hidePanelTitles\":false}", - "panelsJSON": "[{\"type\":\"search\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"d75a68e9-67d9-4bed-9dba-85490d3eec37\"},\"panelIndex\":\"d75a68e9-67d9-4bed-9dba-85490d3eec37\",\"embeddableConfig\":{\"description\":\"\",\"enhancements\":{}},\"title\":\"logstash hits\",\"panelRefName\":\"panel_d75a68e9-67d9-4bed-9dba-85490d3eec37\"}]", - "timeFrom": "2018-04-10T00:00:00.000Z", - "title": "Test Control Group With Multiple Data Views", - "timeTo": "2018-11-15T00:00:00.000Z" - }, - "references": [ - { - "name": "d75a68e9-67d9-4bed-9dba-85490d3eec37:panel_d75a68e9-67d9-4bed-9dba-85490d3eec37", - "type": "search", - "id": "2b9247e0-6458-11ed-9957-e76caeeb9f75" - }, - { - "name": "controlGroup_265b6a28-9ccb-44ae-83c9-3d7a7cac1961:optionsListControlDataView", - "type": "index-pattern", - "id": "d3d7af60-4c81-11e8-b3d7-01146121b73d" - }, - { - "name": "controlGroup_ed2b93e2-da37-482b-ae43-586a41cc2399:rangeSliderControlDataView", - "type": "index-pattern", - "id": "d3d7af60-4c81-11e8-b3d7-01146121b73d" - }, - { - "name": "controlGroup_5e1b146b-8a8b-4117-9218-c4aeaee7bc9a:optionsListControlDataView", - "type": "index-pattern", - "id": "0bf35f60-3dc9-11e8-8660-4d65aa086b3c" - }, - { - "name": "controlGroup_c4760951-e793-45d5-a6b7-c72c145af7f9:rangeSliderControlDataView", - "type": "index-pattern", - "id": "0bf35f60-3dc9-11e8-8660-4d65aa086b3c" - } - ], - "managed": false, - "coreMigrationVersion": "8.8.0", - "typeMigrationVersion": "10.2.0" -} \ No newline at end of file diff --git a/test/functional/page_objects/dashboard_page_controls.ts b/test/functional/page_objects/dashboard_page_controls.ts index dcc43432dab28..a3573438124e5 100644 --- a/test/functional/page_objects/dashboard_page_controls.ts +++ b/test/functional/page_objects/dashboard_page_controls.ts @@ -475,11 +475,7 @@ export class DashboardPageControls extends FtrService { await this.optionsListWaitForLoading(controlId); if (!skipOpen) await this.optionsListOpenPopover(controlId); await this.retry.try(async () => { - const availableOptions = await this.optionsListPopoverGetAvailableOptions(); - expect(availableOptions.suggestions).to.eql(expectation.suggestions); - expect(availableOptions.invalidSelections.sort()).to.eql( - expectation.invalidSelections.sort() - ); + expect(await this.optionsListPopoverGetAvailableOptions()).to.eql(expectation); }); if (await this.testSubjects.exists('optionsList-cardinality-label')) { expect(await this.optionsListGetCardinalityValue()).to.be( @@ -500,9 +496,7 @@ export class DashboardPageControls extends FtrService { public async optionsListPopoverSearchForOption(search: string) { this.log.debug(`searching for ${search} in options list`); await this.optionsListPopoverAssertOpen(); - await this.testSubjects.setValue(`optionsList-control-search-input`, search, { - typeCharByChar: true, - }); + await this.testSubjects.setValue(`optionsList-control-search-input`, search); await this.optionsListPopoverWaitForLoading(); } diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/metrics/static_dashboard/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/metrics/static_dashboard/index.tsx index 6f2c91dec9bfe..752e52aa27c4a 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/metrics/static_dashboard/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/metrics/static_dashboard/index.tsx @@ -16,7 +16,8 @@ import { import { DataView } from '@kbn/data-views-plugin/common'; import { buildExistsFilter, buildPhraseFilter, Filter } from '@kbn/es-query'; import { i18n } from '@kbn/i18n'; -import { controlGroupStateBuilder } from '@kbn/controls-plugin/public'; +import { controlGroupInputBuilder } from '@kbn/controls-plugin/public'; +import { getDefaultControlGroupInput } from '@kbn/controls-plugin/common'; import { NotificationsStart } from '@kbn/core/public'; import { ENVIRONMENT_ALL, @@ -70,9 +71,10 @@ async function getCreationOptions( dataView: DataView ): Promise { try { - const controlGroupState = {}; + const builder = controlGroupInputBuilder; + const controlGroupInput = getDefaultControlGroupInput(); - await controlGroupStateBuilder.addDataControlFromField(controlGroupState, { + await builder.addDataControlFromField(controlGroupInput, { dataViewId: dataView.id ?? '', title: 'Node name', fieldName: 'service.node.name', @@ -90,7 +92,7 @@ async function getCreationOptions( getInitialInput: () => ({ viewMode: ViewMode.VIEW, panels, - controlGroupState, + controlGroupInput, }), }; } catch (error) { From 7cb2a59be5d7c1d6066180a7765c05c777dbbd33 Mon Sep 17 00:00:00 2001 From: "elastic-renovate-prod[bot]" <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> Date: Wed, 4 Sep 2024 13:17:16 -0500 Subject: [PATCH 04/99] Update dependency selenium-webdriver to ^4.24.0 (main) (#192113) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [selenium-webdriver](https://togithub.com/SeleniumHQ/selenium/tree/trunk/javascript/node/selenium-webdriver#readme) ([source](https://togithub.com/SeleniumHQ/selenium)) | devDependencies | minor | [`^4.23.0` -> `^4.24.0`](https://renovatebot.com/diffs/npm/selenium-webdriver/4.23.0/4.24.0) | --- ### Release Notes
SeleniumHQ/selenium (selenium-webdriver) ### [`v4.24.0`](https://togithub.com/SeleniumHQ/selenium/compare/4df0a231af83908edb1a4304028b508f245d26a8...748ffc9bc3cf40211b27d1b27e238b26aae93f46) [Compare Source](https://togithub.com/SeleniumHQ/selenium/compare/4df0a231af83908edb1a4304028b508f245d26a8...748ffc9bc3cf40211b27d1b27e238b26aae93f46)
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://togithub.com/renovatebot/renovate). Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 1380fea8eeea2..e9645353fbb99 100644 --- a/package.json +++ b/package.json @@ -1774,7 +1774,7 @@ "rxjs-marbles": "^7.0.1", "sass-embedded": "^1.77.8", "sass-loader": "^10.5.1", - "selenium-webdriver": "^4.23.0", + "selenium-webdriver": "^4.24.0", "sharp": "0.32.6", "simple-git": "^3.16.0", "sinon": "^7.4.2", diff --git a/yarn.lock b/yarn.lock index cda35fbc6a9cd..383addbf0098b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -28241,15 +28241,15 @@ select-hose@^2.0.0: resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= -selenium-webdriver@^4.23.0: - version "4.23.0" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.23.0.tgz#6d9d219a560dffff1fbbc0f2c8a115d81d279a21" - integrity sha512-DdvtInpnMt95Td8VApvmAw7oSydBD9twIRXqoMyRoGMvL1dAnMFxdrwnW6L0d/pF/uoNTjbVUarwGZ9wIGNStA== +selenium-webdriver@^4.24.0: + version "4.24.0" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.24.0.tgz#bf7563f9e0b1ef29d55f215a8fb187b21e4de26e" + integrity sha512-qrqoHhHPZuKLiz5VAQUxrn3ILs7/cYqn2/x96r35g5JjkLUjOS1lX+F+tEJKhRMlQ/MGJ+N1016JF5g2xZUFzw== dependencies: "@bazel/runfiles" "^5.8.1" jszip "^3.10.1" tmp "^0.2.3" - ws "^8.17.1" + ws "^8.18.0" self-signed-cert@^1.0.1: version "1.0.1" @@ -32479,7 +32479,7 @@ ws@^7.3.1, ws@^7.4.2: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== -ws@^8.17.1, ws@^8.18.0, ws@^8.2.3, ws@^8.4.2, ws@^8.9.0: +ws@^8.18.0, ws@^8.2.3, ws@^8.4.2, ws@^8.9.0: version "8.18.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== From fd704de26fba64ebfb172899dc09c0e65ef5b144 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Wed, 4 Sep 2024 15:04:25 -0400 Subject: [PATCH 05/99] [Synthetics] [ON Week] Refactor Synthetics Overview page for increased scalability (#187092) ## Summary Resolves https://github.com/elastic/kibana/issues/183622. This is part of some ON Week PoC work I did that introduces [React Window](https://github.com/bvaughn/react-window) and its [Infinite Loader](https://github.com/bvaughn/react-window-infinite-loader) to the Synthetics Overview page. Additionally, I have refactored the way that duration fetching is done for the overview cards; the fetching is now handled at a top-level and as-needed during the infinite scroll. This results in a page that is scrollable all the way to the end of very large amounts of monitors. The example deployment I'm using has about 900 monitors, and in the latest versions of Kibana this dataset causes the overview page to crash the tab. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Shahzad --- package.json | 3 + .../common/constants/synthetics/rest_api.ts | 1 + .../monitor_management/monitor_types.ts | 1 + .../synthetics/common/types/index.ts | 1 + .../synthetics/common/types/overview.ts | 32 +++ .../grid_by_group/grid_group_item.tsx | 5 +- .../grid_by_group/grid_items_by_group.tsx | 2 +- .../overview/overview/metric_item.tsx | 56 +++-- .../overview/overview/overview_grid.test.tsx | 191 ---------------- .../overview/overview/overview_grid.tsx | 212 +++++++++++++----- .../overview/overview/overview_grid_item.tsx | 50 ----- .../monitors_page/overview/overview/types.ts | 13 ++ .../public/apps/synthetics/hooks/index.ts | 2 - .../hooks/use_last_50_duration_chart.test.ts | 186 --------------- .../hooks/use_last_50_duration_chart.ts | 87 ------- .../hooks/use_last_x_checks.test.tsx | 203 ----------------- .../synthetics/hooks/use_last_x_checks.ts | 97 -------- .../hooks/use_monitors_sorted_by_status.tsx | 5 +- .../apps/synthetics/state/overview/actions.ts | 11 +- .../apps/synthetics/state/overview/api.ts | 6 +- .../synthetics/state/overview/effects.test.ts | 178 +++++++++++++++ .../apps/synthetics/state/overview/effects.ts | 74 +++++- .../apps/synthetics/state/overview/index.ts | 14 ++ .../apps/synthetics/state/overview/models.ts | 3 + .../synthetics/state/overview/selectors.ts | 4 + .../apps/synthetics/state/root_effect.ts | 8 +- .../__mocks__/synthetics_store.mock.ts | 1 + .../synthetics/server/lib.ts | 4 +- .../synthetics/server/routes/index.ts | 2 + .../routes/overview_trends/fetch_trends.ts | 92 ++++++++ .../routes/overview_trends/overview_trends.ts | 74 ++++++ yarn.lock | 20 +- 32 files changed, 738 insertions(+), 900 deletions(-) create mode 100644 x-pack/plugins/observability_solution/synthetics/common/types/overview.ts delete mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_grid.test.tsx delete mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_grid_item.tsx create mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/types.ts delete mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_last_50_duration_chart.test.ts delete mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_last_50_duration_chart.ts delete mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_last_x_checks.test.tsx delete mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_last_x_checks.ts create mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/effects.test.ts create mode 100644 x-pack/plugins/observability_solution/synthetics/server/routes/overview_trends/fetch_trends.ts create mode 100644 x-pack/plugins/observability_solution/synthetics/server/routes/overview_trends/overview_trends.ts diff --git a/package.json b/package.json index e9645353fbb99..552b585167337 100644 --- a/package.json +++ b/package.json @@ -1201,11 +1201,13 @@ "react-use": "^15.3.8", "react-virtualized": "^9.22.5", "react-window": "^1.8.10", + "react-window-infinite-loader": "^1.0.9", "reduce-reducers": "^1.0.4", "redux": "^4.2.1", "redux-actions": "^2.6.5", "redux-devtools-extension": "^2.13.8", "redux-saga": "^1.1.3", + "redux-saga-testing": "^2.0.2", "redux-thunk": "^2.4.2", "redux-thunks": "^1.0.0", "reflect-metadata": "^0.2.1", @@ -1597,6 +1599,7 @@ "@types/react-test-renderer": "^17.0.2", "@types/react-virtualized": "^9.21.22", "@types/react-window": "^1.8.8", + "@types/react-window-infinite-loader": "^1.0.9", "@types/redux-actions": "^2.6.1", "@types/resolve": "^1.20.1", "@types/seedrandom": ">=2.0.0 <4.0.0", diff --git a/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics/rest_api.ts b/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics/rest_api.ts index 0003360c707b6..23ac30a5ff7b1 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics/rest_api.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics/rest_api.ts @@ -26,6 +26,7 @@ export enum SYNTHETICS_API_URLS { SYNTHETICS_OVERVIEW = '/internal/synthetics/overview', PINGS = '/internal/synthetics/pings', PING_STATUSES = '/internal/synthetics/ping_statuses', + OVERVIEW_TRENDS = '/internal/synthetics/overview_trends', OVERVIEW_STATUS = `/internal/synthetics/overview_status`, INDEX_SIZE = `/internal/synthetics/index_size`, AGENT_POLICIES = `/internal/synthetics/agent_policies`, diff --git a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/monitor_types.ts b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/monitor_types.ts index 6f0ef862137e1..c0383eaea8b39 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/monitor_types.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/monitor_types.ts @@ -395,6 +395,7 @@ export const MonitorOverviewItemCodec = t.intersection([ schedule: t.string, }), t.partial({ + status: t.string, projectId: t.string, }), ]); diff --git a/x-pack/plugins/observability_solution/synthetics/common/types/index.ts b/x-pack/plugins/observability_solution/synthetics/common/types/index.ts index be369427c47e7..6544898d54a64 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/types/index.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/types/index.ts @@ -8,3 +8,4 @@ export * from './synthetics_monitor'; export * from './monitor_validation'; export * from './default_alerts'; +export * from './overview'; diff --git a/x-pack/plugins/observability_solution/synthetics/common/types/overview.ts b/x-pack/plugins/observability_solution/synthetics/common/types/overview.ts new file mode 100644 index 0000000000000..4982f0f408fcf --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/common/types/overview.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. + */ + +export interface TrendKey { + configId: string; + locationId: string; +} + +export type TrendRequest = TrendKey & { schedule: string }; + +export interface TrendDatum { + x: number; + y: number; +} + +export interface OverviewTrend { + configId: string; + locationId: string; + data: TrendDatum[]; + count: number; + min: number; + max: number; + avg: number; + sum: number; + median: number; +} + +export type TrendTable = Record; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/grid_by_group/grid_group_item.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/grid_by_group/grid_group_item.tsx index 7fea62b348edd..5b024f3c70331 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/grid_by_group/grid_group_item.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/grid_by_group/grid_group_item.tsx @@ -23,8 +23,9 @@ import { useKey } from 'react-use'; import { OverviewLoader } from '../overview_loader'; import { useFilteredGroupMonitors } from './use_filtered_group_monitors'; import { MonitorOverviewItem } from '../../types'; -import { FlyoutParamProps, OverviewGridItem } from '../overview_grid_item'; import { selectOverviewStatus } from '../../../../../state/overview_status'; +import { MetricItem } from '../metric_item'; +import { FlyoutParamProps } from '../types'; const PER_ROW = 4; const DEFAULT_ROW_SIZE = 2; @@ -163,7 +164,7 @@ export const GroupGridItem = ({ key={`${monitor.id}-${monitor.location?.id}`} data-test-subj="syntheticsOverviewGridItem" > - + ))} diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/grid_by_group/grid_items_by_group.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/grid_by_group/grid_items_by_group.tsx index e9069d6dfdf7c..ad7d406d76946 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/grid_by_group/grid_items_by_group.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/grid_by_group/grid_items_by_group.tsx @@ -18,8 +18,8 @@ import { import { useFilters } from '../../../common/monitor_filters/use_filters'; import { GroupGridItem } from './grid_group_item'; import { ConfigKey, MonitorOverviewItem } from '../../../../../../../../common/runtime_types'; -import { FlyoutParamProps } from '../overview_grid_item'; import { selectOverviewState, selectServiceLocationsState } from '../../../../../state'; +import { FlyoutParamProps } from '../types'; export const GridItemsByGroup = ({ loaded, diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item.tsx index 516c545f3e680..57c50bc54a5bf 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item.tsx @@ -6,16 +6,21 @@ */ import { i18n } from '@kbn/i18n'; import React, { useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/react'; import { Chart, Settings, Metric, MetricTrendShape } from '@elastic/charts'; -import { EuiPanel } from '@elastic/eui'; +import { EuiPanel, EuiSpacer } from '@elastic/eui'; import { DARK_THEME } from '@elastic/charts'; import { useTheme } from '@kbn/observability-shared-plugin/public'; -import { useDispatch, useSelector } from 'react-redux'; import moment from 'moment'; +import { useSelector, useDispatch } from 'react-redux'; + import { MetricItemBody } from './metric_item/metric_item_body'; -import { MetricItemExtra } from './metric_item/metric_item_extra'; -import { selectErrorPopoverState, toggleErrorPopoverOpen } from '../../../../state'; +import { + selectErrorPopoverState, + selectOverviewTrends, + toggleErrorPopoverOpen, +} from '../../../../state'; import { useLocationName, useStatusByLocationOverview } from '../../../../hooks'; import { formatDuration } from '../../../../utils/formatting'; import { MonitorOverviewItem } from '../../../../../../../common/runtime_types'; @@ -26,6 +31,9 @@ import { toggleTestNowFlyoutAction, } from '../../../../state/manual_test_runs'; import { MetricItemIcon } from './metric_item_icon'; +import { MetricItemExtra } from './metric_item/metric_item_extra'; + +const METRIC_ITEM_HEIGHT = 160; export const getColor = ( theme: ReturnType, @@ -49,20 +57,14 @@ export const getColor = ( export const MetricItem = ({ monitor, - stats, - data, onClick, + style, }: { monitor: MonitorOverviewItem; - data: Array<{ x: number; y: number }>; - stats: { - medianDuration: number; - avgDuration: number; - minDuration: number; - maxDuration: number; - }; + style?: React.CSSProperties; onClick: (params: { id: string; configId: string; location: string; locationId: string }) => void; }) => { + const trendData = useSelector(selectOverviewTrends)[monitor.configId + monitor.location.id]; const [isPopoverOpen, setIsPopoverOpen] = useState(false); const isErrorPopoverOpen = useSelector(selectErrorPopoverState); const locationName = useLocationName(monitor); @@ -77,7 +79,10 @@ export const MetricItem = ({ const dispatch = useDispatch(); return ( -
+
, + trend: trendData?.data ?? [], + extra: trendData ? ( + + ) : ( +
+ +
+ ), valueFormatter: (d: number) => formatDuration(d), color: getColor(theme, monitor.isEnabled, status), body: , @@ -167,6 +188,7 @@ export const MetricItem = ({ /> )}
+
); }; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_grid.test.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_grid.test.tsx deleted file mode 100644 index 3ea7d5e0ba5b3..0000000000000 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_grid.test.tsx +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { render } from '../../../../utils/testing/rtl_helpers'; -import { waitFor } from '@testing-library/react'; -import { MonitorOverviewItem } from '../types'; -import { OverviewGrid } from './overview_grid'; -import * as hooks from '../../../../hooks/use_last_50_duration_chart'; - -describe('Overview Grid', () => { - const locationIdToName: Record = { - us_central: 'Us Central', - us_east: 'US East', - }; - const getMockData = (): MonitorOverviewItem[] => { - const data: MonitorOverviewItem[] = []; - for (let i = 0; i < 20; i++) { - data.push({ - id: `${i}`, - configId: `${i}`, - location: { - id: 'us_central', - isServiceManaged: true, - }, - name: `Monitor ${i}`, - isEnabled: true, - isStatusAlertEnabled: true, - type: 'browser', - tags: [], - schedule: '60', - }); - data.push({ - id: `${i}`, - configId: `${i}`, - location: { - id: 'us_east', - isServiceManaged: true, - }, - name: `Monitor ${i}`, - isEnabled: true, - isStatusAlertEnabled: true, - type: 'browser', - tags: [], - schedule: '60', - }); - } - return data; - }; - - const getMockChart = (): Array<{ x: number; y: number }> => { - const hits = []; - for (let i = 0; i < 20; i++) { - hits.push({ - x: i, - y: i, - }); - } - return hits; - }; - - const perPage = 20; - - it('renders correctly', async () => { - jest.spyOn(hooks, 'useLast50DurationChart').mockReturnValue({ - data: getMockChart(), - avgDuration: 30000, - minDuration: 0, - maxDuration: 50000, - medianDuration: 15000, - loading: false, - }); - - const { getByText, getAllByTestId, queryByText } = render(, { - state: { - overview: { - pageState: { - perPage, - }, - data: { - monitors: getMockData(), - allMonitorIds: [], // not critical for this test - total: getMockData().length, - }, - loaded: true, - loading: false, - }, - overviewStatus: { - status: { - downConfigs: {}, - upConfigs: {}, - allConfigs: getMockData().reduce((acc, cur) => { - acc[`${cur.id}-${locationIdToName[cur.location.id]}`] = { - configId: cur.configId, - monitorQueryId: cur.id, - location: locationIdToName[cur.location.id], - status: 'down', - }; - return acc; - }, {} as Record), - }, - }, - serviceLocations: { - locations: [ - { - id: 'us_central', - label: 'Us Central', - }, - { - id: 'us_east', - label: 'US East', - }, - ], - locationsLoaded: true, - loading: false, - }, - }, - }); - - await waitFor(() => { - expect(getByText('Showing')).toBeInTheDocument(); - expect(getByText('40')).toBeInTheDocument(); - expect(getByText('Monitors')).toBeInTheDocument(); - expect(queryByText('Showing all monitors')).not.toBeInTheDocument(); - expect(getAllByTestId('syntheticsOverviewGridItem').length).toEqual(perPage); - }); - }); - - it('displays showing all monitors label when reaching the end of the list', async () => { - jest.spyOn(hooks, 'useLast50DurationChart').mockReturnValue({ - data: getMockChart(), - avgDuration: 30000, - minDuration: 0, - maxDuration: 50000, - medianDuration: 15000, - loading: false, - }); - - const { getByText } = render(, { - state: { - overview: { - pageState: { - perPage, - }, - data: { - monitors: getMockData().slice(0, 16), - allMonitorIds: [], // not critical for this test - total: getMockData().length, - }, - loaded: true, - loading: false, - }, - overviewStatus: { - status: { - downConfigs: {}, - upConfigs: {}, - allConfigs: getMockData().reduce((acc, cur) => { - acc[`${cur.id}-${locationIdToName[cur.location.id]}`] = { - configId: cur.configId, - monitorQueryId: cur.id, - location: locationIdToName[cur.location.id], - status: 'down', - }; - return acc; - }, {} as Record), - }, - }, - serviceLocations: { - locations: [ - { - id: 'us_central', - label: 'Us Central', - }, - { - id: 'us_east', - label: 'US East', - }, - ], - locationsLoaded: true, - loading: false, - }, - }, - }); - - expect(getByText('Showing all monitors')).toBeInTheDocument(); - }); -}); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_grid.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_grid.tsx index 3da7b03f3ad9e..76e52685736b1 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_grid.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_grid.tsx @@ -4,55 +4,77 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useState, useRef, memo, useCallback, useEffect } from 'react'; +import React, { useState, memo, useCallback, useEffect, useMemo } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { i18n } from '@kbn/i18n'; +import InfiniteLoader from 'react-window-infinite-loader'; +import { FixedSizeList, ListChildComponentProps } from 'react-window'; import { EuiFlexGroup, EuiFlexItem, - EuiFlexGrid, EuiSpacer, EuiButtonEmpty, EuiText, - EuiProgress, + EuiAutoSizer, + EuiAutoSize, } from '@elastic/eui'; +import type { TrendRequest } from '../../../../../../../common/types'; import { SYNTHETICS_MONITORS_EMBEDDABLE } from '../../../../../embeddables/constants'; import { AddToDashboard } from '../../../common/components/add_to_dashboard'; import { useOverviewStatus } from '../../hooks/use_overview_status'; -import { useInfiniteScroll } from './use_infinite_scroll'; import { GridItemsByGroup } from './grid_by_group/grid_items_by_group'; import { GroupFields } from './grid_by_group/group_fields'; import { fetchMonitorOverviewAction, quietFetchOverviewAction, + refreshOverviewTrends, selectOverviewState, + selectOverviewTrends, setFlyoutConfig, + trendStatsBatch, } from '../../../../state/overview'; -import { useMonitorsSortedByStatus } from '../../../../hooks/use_monitors_sorted_by_status'; import { OverviewLoader } from './overview_loader'; import { OverviewPaginationInfo } from './overview_pagination_info'; -import { FlyoutParamProps, OverviewGridItem } from './overview_grid_item'; import { SortFields } from './sort_fields'; import { NoMonitorsFound } from '../../common/no_monitors_found'; import { MonitorDetailFlyout } from './monitor_detail_flyout'; +import { useSyntheticsRefreshContext } from '../../../../contexts'; +import { MetricItem } from './metric_item'; +import { FlyoutParamProps } from './types'; +import { MonitorOverviewItem } from '../types'; +import { useMonitorsSortedByStatus } from '../../../../hooks/use_monitors_sorted_by_status'; + +const ITEM_HEIGHT = 172; +const ROW_COUNT = 4; +const MAX_LIST_HEIGHT = 800; +const MIN_BATCH_SIZE = 20; +const LIST_THRESHOLD = 12; + +interface ListItem { + configId: string; + location: { id: string }; +} export const OverviewGrid = memo(() => { const { status } = useOverviewStatus({ scopeStatusByLocation: true }); + const monitorsSortedByStatus: MonitorOverviewItem[] = + useMonitorsSortedByStatus().monitorsSortedByStatus; const { data: { monitors }, flyoutConfig, loaded, - loading, pageState, groupBy: { field: groupField }, } = useSelector(selectOverviewState); + const trendData = useSelector(selectOverviewTrends); const { perPage } = pageState; + const [page, setPage] = useState(1); + const [maxItem, setMaxItem] = useState(0); + const [currentIndex, setCurrentIndex] = useState(0); const dispatch = useDispatch(); - const intersectionRef = useRef(null); - const { monitorsSortedByStatus } = useMonitorsSortedByStatus(); // fetch overview for all other page state changes useEffect(() => { @@ -64,12 +86,46 @@ export const OverviewGrid = memo(() => { [dispatch] ); const hideFlyout = useCallback(() => dispatch(setFlyoutConfig(null)), [dispatch]); + const { lastRefresh } = useSyntheticsRefreshContext(); const forceRefreshCallback = useCallback( () => dispatch(quietFetchOverviewAction.get(pageState)), [dispatch, pageState] ); - const { currentMonitors } = useInfiniteScroll({ intersectionRef, monitorsSortedByStatus }); + useEffect(() => { + if (monitorsSortedByStatus.length && maxItem) { + const batch: TrendRequest[] = []; + const chunk = monitorsSortedByStatus.slice(0, (maxItem + 1) * ROW_COUNT); + for (const item of chunk) { + if (trendData[item.configId + item.location.id] === undefined) { + batch.push({ + configId: item.configId, + locationId: item.location.id, + schedule: item.schedule, + }); + } + } + if (batch.length) dispatch(trendStatsBatch.get(batch)); + } + }, [dispatch, maxItem, monitorsSortedByStatus, trendData]); + + const listHeight = Math.min( + ITEM_HEIGHT * Math.ceil(monitorsSortedByStatus.length / ROW_COUNT), + MAX_LIST_HEIGHT + ); + + const listItems: ListItem[][] = useMemo(() => { + const acc: ListItem[][] = []; + for (let i = 0; i < monitorsSortedByStatus.length; i += ROW_COUNT) { + acc.push(monitorsSortedByStatus.slice(i, i + ROW_COUNT)); + } + return acc; + }, [monitorsSortedByStatus]); + + const listRef: React.LegacyRef> | undefined = React.createRef(); + useEffect(() => { + dispatch(refreshOverviewTrends.get()); + }, [dispatch, lastRefresh]); // Display no monitors found when down, up, or disabled filter produces no results if (status && !monitorsSortedByStatus.length && loaded) { @@ -102,63 +158,111 @@ export const OverviewGrid = memo(() => { - - {loading && } - - <> + +
{groupField === 'none' ? ( - loaded && currentMonitors.length ? ( - - {currentMonitors.map((monitor) => ( - + {({ width }: EuiAutoSize) => ( + + listItems[idx].every((m) => !!trendData[m.configId + m.location.id]) + } + itemCount={listItems.length} + loadMoreItems={(_start: number, stop: number) => + setMaxItem(Math.max(maxItem, stop)) + } + minimumBatchSize={MIN_BATCH_SIZE} + threshold={LIST_THRESHOLD} > - - - ))} - + {({ onItemsRendered }) => ( + + {({ + index: listIndex, + style, + data: listData, + }: React.PropsWithChildren>) => { + setCurrentIndex(listIndex); + return ( + + {listData[listIndex].map((_, idx) => ( + + + + ))} + {listData[listIndex].length % ROW_COUNT !== 0 && + // Adds empty items to fill out row + Array.from({ + length: ROW_COUNT - listData[listIndex].length, + }).map((_, idx) => )} + + ); + }} + + )} + + )} + ) : ( ) ) : ( )} - -
-
- {groupField === 'none' && ( - - {currentMonitors.length === monitors.length && ( - - {SHOWING_ALL_MONITORS_LABEL} - - )} - {currentMonitors.length === monitors.length && currentMonitors.length > perPage && ( - - window.scrollTo(0, 0)} - iconType="sortUp" - iconSide="right" - size="xs" - > - {SCROLL_TO_TOP_LABEL} - - - )} - - )} + {groupField === 'none' && + loaded && + // display this footer when user scrolls to end of list + currentIndex * ROW_COUNT + ROW_COUNT >= monitorsSortedByStatus.length && ( + <> + + + {monitorsSortedByStatus.length === monitors.length && ( + + {SHOWING_ALL_MONITORS_LABEL} + + )} + {monitorsSortedByStatus.length === monitors.length && + monitorsSortedByStatus.length > perPage && ( + + { + window.scrollTo({ top: 0, left: 0, behavior: 'smooth' }); + listRef.current?.scrollToItem(0); + }} + iconType="sortUp" + iconSide="right" + size="xs" + > + {SCROLL_TO_TOP_LABEL} + + + )} + + + )} {flyoutConfig?.configId && flyoutConfig?.location && ( void; -}) => { - const { timestamp } = useStatusByLocationOverview({ - configId: monitor.configId, - locationId: monitor.location.id, - }); - - const { data, medianDuration, maxDuration, avgDuration, minDuration } = useLast50DurationChart({ - locationId: monitor.location?.id, - monitorId: monitor.id, - timestamp, - schedule: monitor.schedule, - }); - return ( - - ); -}; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/types.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/types.ts new file mode 100644 index 0000000000000..a2e7d8581e657 --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/types.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface FlyoutParamProps { + id: string; + configId: string; + location: string; + locationId: string; +} diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/index.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/index.ts index 2e5d9e2f76d66..ce0163ff74fb9 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/index.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/index.ts @@ -10,8 +10,6 @@ export * from './use_url_params'; export * from './use_breadcrumbs'; export * from './use_enablement'; export * from './use_locations'; -export * from './use_last_x_checks'; -export * from './use_last_50_duration_chart'; export * from './use_location_name'; export * from './use_status_by_location'; export * from './use_status_by_location_overview'; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_last_50_duration_chart.test.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_last_50_duration_chart.test.ts deleted file mode 100644 index 4c149ce74667f..0000000000000 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_last_50_duration_chart.test.ts +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook } from '@testing-library/react-hooks'; -import * as hooks from './use_last_x_checks'; -import { useLast50DurationChart } from './use_last_50_duration_chart'; -import { WrappedHelper } from '../utils/testing'; - -describe('useLast50DurationChart', () => { - const getMockHits = (): Array<{ 'monitor.duration.us': number[] | undefined }> => { - const hits = []; - for (let i = 0; i < 10; i++) { - hits.push({ - 'monitor.duration.us': [i], - }); - } - return hits; - }; - - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('returns expected results', () => { - jest.spyOn(hooks, 'useLastXChecks').mockReturnValue({ hits: getMockHits(), loading: false }); - - const { result } = renderHook( - () => useLast50DurationChart({ monitorId: 'mock-id', locationId: 'loc', schedule: '1' }), - { wrapper: WrappedHelper } - ); - expect(result.current).toEqual({ - medianDuration: 5, - maxDuration: 9, - minDuration: 0, - avgDuration: 4.5, - data: [ - { - x: 0, - y: 9, - }, - { - x: 1, - y: 8, - }, - { - x: 2, - y: 7, - }, - { - x: 3, - y: 6, - }, - { - x: 4, - y: 5, - }, - { - x: 5, - y: 4, - }, - { - x: 6, - y: 3, - }, - { - x: 7, - y: 2, - }, - { - x: 8, - y: 1, - }, - { - x: 9, - y: 0, - }, - ], - loading: false, - }); - }); - - it('handles undefined monitor duration', () => { - const hitsWithAnUndefinedDuration = [...getMockHits()]; - hitsWithAnUndefinedDuration[1] = { 'monitor.duration.us': undefined }; - - jest - .spyOn(hooks, 'useLastXChecks') - .mockReturnValue({ hits: hitsWithAnUndefinedDuration, loading: false }); - const { result } = renderHook( - () => useLast50DurationChart({ monitorId: 'mock-id', locationId: 'loc', schedule: '10' }), - { wrapper: WrappedHelper } - ); - - const data = [ - { - x: 0, - y: 9, - }, - { - x: 1, - y: 8, - }, - { - x: 2, - y: 7, - }, - { - x: 3, - y: 6, - }, - { - x: 4, - y: 5, - }, - { - x: 5, - y: 4, - }, - { - x: 6, - y: 3, - }, - { - x: 7, - y: 2, - }, - { - x: 9, - y: 0, - }, - ]; - - expect(result.current).toEqual({ - medianDuration: [...data].sort((a, b) => a.y - b.y)[Math.floor(data.length / 2)].y, - maxDuration: 9, - minDuration: 0, - avgDuration: 4.4, - data, - loading: false, - }); - }); - - it('passes proper params to useLastXChecks', () => { - const hitsWithAnUndefinedDuration = [...getMockHits()]; - hitsWithAnUndefinedDuration[1] = { 'monitor.duration.us': undefined }; - const monitorId = 'mock-id'; - const locationId = 'loc'; - - const spy = jest - .spyOn(hooks, 'useLastXChecks') - .mockReturnValue({ hits: hitsWithAnUndefinedDuration, loading: false }); - renderHook(() => useLast50DurationChart({ monitorId, locationId, schedule: '120' }), { - wrapper: WrappedHelper, - }); - - expect(spy).toBeCalledTimes(1); - expect(spy).toBeCalledWith({ - monitorId, - locationId, - fields: ['monitor.duration.us'], - size: 50, - schedule: '120', - }); - }); - - it('returns loading properly', () => { - const loading = true; - - jest.spyOn(hooks, 'useLastXChecks').mockReturnValue({ hits: getMockHits(), loading }); - const { result } = renderHook( - () => useLast50DurationChart({ monitorId: 'mock-id', locationId: 'loc', schedule: '3' }), - { wrapper: WrappedHelper } - ); - renderHook( - () => useLast50DurationChart({ monitorId: 'test-id', locationId: 'loc', schedule: '5' }), - { - wrapper: WrappedHelper, - } - ); - expect(result.current.loading).toEqual(loading); - }); -}); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_last_50_duration_chart.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_last_50_duration_chart.ts deleted file mode 100644 index f08e025a48540..0000000000000 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_last_50_duration_chart.ts +++ /dev/null @@ -1,87 +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 { useLastXChecks } from './use_last_x_checks'; - -const fields = ['monitor.duration.us']; - -export function useLast50DurationChart({ - monitorId, - locationId, - timestamp, - schedule, -}: { - monitorId: string; - timestamp?: string; - locationId: string; - schedule: string; -}) { - const { hits, loading } = useLastXChecks<{ - 'monitor.duration.us': number[] | undefined; - }>({ - monitorId, - locationId, - fields, - size: 50, - timestamp, - schedule, - }); - const { data, median, min, max, avg } = useMemo(() => { - if (loading) { - return { - data: [], - median: 0, - avg: 0, - min: 0, - max: 0, - }; - } - - // calculate min, max, average duration and median - - const coords = hits - .reverse() // results are returned in desc order by timestamp. Reverse to ensure the data is in asc order by timestamp - .map((hit, index) => { - const duration = hit?.['monitor.duration.us']?.[0]; - if (duration === undefined) { - return null; - } - return { - x: index, - y: duration, - }; - }) - .filter((item) => item !== null); - - const sortedByDuration = [...hits].sort( - (a, b) => (a?.['monitor.duration.us']?.[0] || 0) - (b?.['monitor.duration.us']?.[0] || 0) - ); - - return { - data: coords as Array<{ x: number; y: number }>, - median: sortedByDuration[Math.floor(hits.length / 2)]?.['monitor.duration.us']?.[0] || 0, - avg: - sortedByDuration.reduce((acc, curr) => acc + (curr?.['monitor.duration.us']?.[0] || 0), 0) / - hits.length, - min: sortedByDuration[0]?.['monitor.duration.us']?.[0] || 0, - max: sortedByDuration[sortedByDuration.length - 1]?.['monitor.duration.us']?.[0] || 0, - }; - }, [hits, loading]); - - return useMemo( - () => ({ - data, - medianDuration: median, - avgDuration: avg, - minDuration: min, - maxDuration: max, - loading, - }), - [data, median, avg, min, max, loading] - ); -} diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_last_x_checks.test.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_last_x_checks.test.tsx deleted file mode 100644 index 8c16902357273..0000000000000 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_last_x_checks.test.tsx +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; -import { getTimeRangeFilter, useLastXChecks } from './use_last_x_checks'; -import { WrappedHelper } from '../utils/testing'; -import * as searchHooks from './use_redux_es_search'; -import { SYNTHETICS_INDEX_PATTERN } from '../../../../common/constants'; - -describe('useLastXChecks', () => { - const getMockHits = (): Array<{ fields: { 'monitor.duration.us': number[] | undefined } }> => { - const hits = []; - for (let i = 0; i < 10; i++) { - hits.push({ - fields: { - 'monitor.duration.us': [i], - }, - }); - } - return hits; - }; - - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('returns expected results', () => { - jest.spyOn(searchHooks, 'useReduxEsSearch').mockReturnValue({ - data: { hits: { hits: getMockHits() } }, - } as any); - - const { result } = renderHook( - () => - useLastXChecks({ - monitorId: 'mock-id', - locationId: 'loc', - size: 30, - fields: ['monitor.duration.us'], - schedule: '10', - }), - { wrapper: WrappedHelper } - ); - expect(result.current).toEqual({ - hits: [ - { - 'monitor.duration.us': [0], - }, - { - 'monitor.duration.us': [1], - }, - { - 'monitor.duration.us': [2], - }, - { - 'monitor.duration.us': [3], - }, - { - 'monitor.duration.us': [4], - }, - { - 'monitor.duration.us': [5], - }, - { - 'monitor.duration.us': [6], - }, - { - 'monitor.duration.us': [7], - }, - { - 'monitor.duration.us': [8], - }, - { - 'monitor.duration.us': [9], - }, - ], - loading: false, - }); - }); - - it('passes proper params', () => { - const spy = jest.spyOn(searchHooks, 'useReduxEsSearch').mockReturnValue({ - data: { hits: { hits: getMockHits() } }, - } as any); - - const fields = ['monitor.summary']; - const size = 30; - - renderHook( - () => - useLastXChecks({ - monitorId: 'mock-id', - locationId: 'loc', - size, - fields, - schedule: '120', - }), - { wrapper: WrappedHelper } - ); - expect(spy).toBeCalledTimes(1); - expect(spy).toBeCalledWith( - expect.objectContaining({ body: expect.objectContaining({ fields, size }) }), - expect.anything(), - expect.anything() - ); - }); - - it('returns loading properly', () => { - jest.spyOn(searchHooks, 'useReduxEsSearch').mockReturnValue({ - data: { hits: { hits: getMockHits() } }, - } as any); - - const { result } = renderHook( - () => - useLastXChecks({ - monitorId: 'mock-id', - locationId: 'loc', - size: 30, - fields: ['monitor.duration.us'], - schedule: '240', - }), - { wrapper: WrappedHelper } - ); - expect(result.current.loading).toEqual(false); - }); - - it('returns loading true when there is no data', () => { - jest.spyOn(searchHooks, 'useReduxEsSearch').mockReturnValue({ - data: undefined, - } as any); - - const { result } = renderHook( - () => - useLastXChecks({ - monitorId: 'mock-id', - locationId: 'loc', - size: 30, - fields: ['monitor.duration.us'], - schedule: '1', - }), - { wrapper: WrappedHelper } - ); - expect(result.current.loading).toEqual(true); - }); - - it('calls useEsSearch with correct index', () => { - const spy = jest.spyOn(searchHooks, 'useReduxEsSearch').mockReturnValue({ - data: { hits: { hits: getMockHits() } }, - } as any); - - const WrapperWithState = ({ children }: { children: React.ReactElement }) => { - return ( - - {children} - - ); - }; - - renderHook( - () => - useLastXChecks({ - monitorId: 'mock-id', - locationId: 'loc', - size: 30, - fields: ['monitor.duration.us'], - schedule: '3', - }), - { wrapper: WrapperWithState } - ); - expect(spy).toBeCalledWith( - expect.objectContaining({ index: SYNTHETICS_INDEX_PATTERN }), - expect.anything(), - expect.anything() - ); - }); -}); - -describe('getTimeRangeFilter', () => { - it.each([ - [1, 'now-1h'], - [3, 'now-3h'], - [5, 'now-5h'], - [10, 'now-9h'], - [60, 'now-50h'], - [120, 'now-100h'], - [240, 'now-200h'], - ])('returns expected filter', (val, res) => { - const filter = getTimeRangeFilter(String(val)); - expect(filter).toEqual({ - range: { - '@timestamp': { - gte: res, - lte: 'now', - }, - }, - }); - }); -}); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_last_x_checks.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_last_x_checks.ts deleted file mode 100644 index 7b155f53272dd..0000000000000 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_last_x_checks.ts +++ /dev/null @@ -1,97 +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 { useSelector } from 'react-redux'; -import { createEsParams } from '@kbn/observability-shared-plugin/public'; -import { useReduxEsSearch } from './use_redux_es_search'; -import { Ping } from '../../../../common/runtime_types'; - -import { - EXCLUDE_RUN_ONCE_FILTER, - getLocationFilter, - FINAL_SUMMARY_FILTER, -} from '../../../../common/constants/client_defaults'; -import { selectServiceLocationsState } from '../state'; -import { useSyntheticsRefreshContext } from '../contexts/synthetics_refresh_context'; -import { SYNTHETICS_INDEX_PATTERN, UNNAMED_LOCATION } from '../../../../common/constants'; - -export const getTimeRangeFilter = (schedule: string) => { - const inMinutes = Number(schedule); - const fiftyChecksInMinutes = inMinutes * 50; - const hours = Math.ceil(fiftyChecksInMinutes / 60); - return { - range: { - '@timestamp': { - gte: `now-${hours}h`, - lte: 'now', - }, - }, - }; -}; - -export function useLastXChecks({ - monitorId, - locationId, - fields = ['*'], - size = 50, - timestamp, - schedule, -}: { - monitorId: string; - schedule: string; - locationId: string; - timestamp?: string; - fields?: string[]; - size?: number; -}) { - const { lastRefresh } = useSyntheticsRefreshContext(); - const { locationsLoaded, locations } = useSelector(selectServiceLocationsState); - - const params = createEsParams({ - index: SYNTHETICS_INDEX_PATTERN, - body: { - size, - query: { - bool: { - filter: [ - FINAL_SUMMARY_FILTER, - EXCLUDE_RUN_ONCE_FILTER, - getTimeRangeFilter(schedule), - { - term: { - 'monitor.id': monitorId, - }, - }, - ], - ...getLocationFilter({ - locationId, - locationName: - locations.find((location) => location.id === locationId)?.label || UNNAMED_LOCATION, - }), - }, - }, - _source: false, - sort: [{ '@timestamp': 'desc' }], - fields, - }, - }); - - const { data } = useReduxEsSearch(params, [lastRefresh], { - name: `zGetLastXChecks/${monitorId}/${locationId}`, - isRequestReady: locationsLoaded && Boolean(timestamp), // don't run query until locations are loaded - }); - - const dataAsJSON = JSON.stringify(data?.hits?.hits); - - return useMemo(() => { - return { - hits: (data?.hits?.hits.map((hit) => hit.fields) as Fields[]) || [], - loading: !data, - }; - }, [dataAsJSON]); // eslint-disable-line react-hooks/exhaustive-deps -} diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.tsx index 73f9644749351..c0a59c31a8760 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.tsx @@ -12,7 +12,10 @@ import { MonitorOverviewItem } from '../../../../common/runtime_types'; import { selectOverviewState } from '../state/overview'; import { useGetUrlParams } from './use_url_params'; -export function useMonitorsSortedByStatus() { +export function useMonitorsSortedByStatus(): { + monitorsSortedByStatus: MonitorOverviewItem[]; + downMonitors: Record | null; +} { const { statusFilter } = useGetUrlParams(); const { status } = useSelector(selectOverviewStatus); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/actions.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/actions.ts index 73e24e6ece6c9..b5098aaa7cbf6 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/actions.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/actions.ts @@ -5,9 +5,10 @@ * 2.0. */ import { createAction } from '@reduxjs/toolkit'; +import { TrendRequest, TrendTable } from '../../../../../common/types'; import { createAsyncAction } from '../utils/actions'; -import { +import type { MonitorOverviewFlyoutConfig, MonitorOverviewPageState, MonitorOverviewState, @@ -33,3 +34,11 @@ export const quietFetchOverviewAction = createAsyncAction< MonitorOverviewPageState, MonitorOverviewResult >('quietFetchOverviewAction'); + +export const refreshOverviewTrends = createAsyncAction( + 'refreshOverviewTrendStats' +); + +export const trendStatsBatch = createAsyncAction( + 'batchTrendStats' +); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/api.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/api.ts index cc496074332b0..2a8e782013651 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/api.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/api.ts @@ -13,8 +13,9 @@ import { OverviewStatus, OverviewStatusCodec, } from '../../../../../common/runtime_types'; +import type { TrendRequest, TrendTable } from '../../../../../common/types'; import { apiService } from '../../../../utils/api_service'; -import { MonitorOverviewPageState } from './models'; +import type { MonitorOverviewPageState } from './models'; function toMonitorOverviewQueryArgs( pageState: MonitorOverviewPageState @@ -58,3 +59,6 @@ export const fetchOverviewStatus = async ( const params = toStatusOverviewQueryArgs(pageState); return apiService.get(SYNTHETICS_API_URLS.OVERVIEW_STATUS, params, OverviewStatusCodec); }; + +export const fetchOverviewTrendStats = async (monitors: TrendRequest[]): Promise => + monitors.length ? apiService.post(SYNTHETICS_API_URLS.OVERVIEW_TRENDS, monitors) : {}; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/effects.test.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/effects.test.ts new file mode 100644 index 0000000000000..ceef406ebbd1b --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/effects.test.ts @@ -0,0 +1,178 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import sagaHelper from 'redux-saga-testing'; +import { call, put, select } from 'redux-saga/effects'; +import { TrendKey, TrendRequest, TrendTable } from '../../../../../common/types'; +import { TRENDS_CHUNK_SIZE, fetchTrendEffect, refreshTrends } from './effects'; +import { trendStatsBatch } from './actions'; +import { fetchOverviewTrendStats as trendsApi } from './api'; +import { selectOverviewState, selectOverviewTrends } from '.'; + +const TEST_TRENDS_LENGTH = 80; + +const generateTrendRequests = () => { + const ar: TrendRequest[] = []; + for (let i = 0; i < TEST_TRENDS_LENGTH; i++) + ar.push({ configId: `configId${i}`, locationId: 'location', schedule: '3' }); + return ar; +}; + +const responseReducer = (acc: Record, curr: TrendKey) => ({ + ...acc, + [curr.configId + curr.locationId]: null, +}); + +describe('overview effects', () => { + describe('fetchTrendEffect', () => { + const trendRequests = generateTrendRequests(); + const firstChunk = trendRequests.slice( + trendRequests.length - TRENDS_CHUNK_SIZE, + trendRequests.length + ); + const secondChunk = trendRequests.slice(0, TEST_TRENDS_LENGTH - TRENDS_CHUNK_SIZE); + const firstChunkResponse = firstChunk.reduce(responseReducer, {}); + const secondChunkResponse = secondChunk.reduce(responseReducer, {}); + + const it = sagaHelper( + fetchTrendEffect(trendStatsBatch.get(trendRequests)) as IterableIterator + ); + + it('calls the `trendsApi` with the first chunk of trend requests', (callResult) => { + expect(callResult).toEqual(call(trendsApi, firstChunk)); + return firstChunkResponse; + }); + + it('sends trends stats success action', (putResult) => { + expect(putResult).toEqual(put(trendStatsBatch.success(firstChunkResponse))); + }); + + it('calls the api for the second chunk', (callResult) => { + expect(callResult).toEqual(call(trendsApi, secondChunk)); + return secondChunkResponse; + }); + + it('sends trends stats success action', (putResult) => { + expect(putResult).toEqual(put(trendStatsBatch.success(secondChunkResponse))); + }); + + it('terminates', (result) => { + expect(result).toBeUndefined(); + }); + }); + + describe('refreshTrends with no data', () => { + const it = sagaHelper(refreshTrends() as IterableIterator); + + it('selects the trends in the table', (selectResult) => { + expect(selectResult).toEqual(select(selectOverviewTrends)); + return { monitor1: null, monitor2: null, monitor3: null }; + }); + + it('selects the overview state', (selectResult) => { + expect(selectResult).toEqual(select(selectOverviewState)); + return { data: { monitors: [] } }; + }); + + it('skips the API if the data is null', (result) => { + expect(result).toBeUndefined(); + }); + }); + + describe('refreshTrends with data', () => { + const it = sagaHelper(refreshTrends() as IterableIterator); + const table: TrendTable = { + monitor1: { + configId: 'monitor1', + locationId: 'location', + data: [{ x: 0, y: 1 }], + count: 1, + median: 1, + min: 0, + max: 0, + avg: 0, + sum: 0, + }, + monitor2: null, + monitor3: { + configId: 'monitor3', + locationId: 'location', + data: [{ x: 0, y: 1 }], + count: 1, + median: 1, + min: 0, + max: 0, + avg: 0, + sum: 0, + }, + }; + + const apiResponse: TrendTable = { + monitor1: { + configId: 'monitor1', + locationId: 'location', + data: [ + { x: 0, y: 1 }, + { x: 1, y: 2 }, + ], + count: 2, + median: 2, + min: 1, + max: 1, + avg: 1, + sum: 1, + }, + monitor2: { + configId: 'monitor2', + locationId: 'location', + data: [ + { x: 0, y: 1 }, + { x: 1, y: 2 }, + ], + count: 2, + median: 2, + min: 1, + max: 1, + avg: 1, + sum: 1, + }, + }; + + it('selects the trends in the table', (selectResult) => { + expect(selectResult).toEqual(select(selectOverviewTrends)); + + return table; + }); + + it('selects the overview state', (selectResults) => { + expect(selectResults).toEqual(select(selectOverviewState)); + return { + data: { + monitors: [ + { configId: 'monitor1', schedule: '3' }, + { configId: 'monitor3', schedule: '3' }, + ], + }, + }; + }); + + it('calls the api for the first chunk', (callResult) => { + expect(callResult).toEqual( + call(trendsApi, [ + { configId: 'monitor1', locationId: 'location', schedule: '3' }, + { configId: 'monitor3', locationId: 'location', schedule: '3' }, + ]) + ); + + return apiResponse; + }); + + it('sends trends stats success action', (putResult) => { + expect(putResult).toEqual(put(trendStatsBatch.success(apiResponse))); + }); + }); +}); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/effects.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/effects.ts index 71821c46665c7..930c729bde4f7 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/effects.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/effects.ts @@ -5,10 +5,18 @@ * 2.0. */ -import { debounce } from 'redux-saga/effects'; +import { debounce, call, takeLeading, takeEvery, put, select } from 'redux-saga/effects'; +import type { TrendTable } from '../../../../../common/types'; import { fetchEffectFactory } from '../utils/fetch_effect'; -import { fetchMonitorOverviewAction, quietFetchOverviewAction } from './actions'; -import { fetchMonitorOverview } from './api'; +import { selectOverviewState, selectOverviewTrends } from './selectors'; +import { + fetchMonitorOverviewAction, + quietFetchOverviewAction, + refreshOverviewTrends, + trendStatsBatch, +} from './actions'; +import { fetchMonitorOverview, fetchOverviewTrendStats as trendsApi } from './api'; +import { MonitorOverviewState } from '.'; export function* fetchMonitorOverviewEffect() { yield debounce( @@ -21,3 +29,63 @@ export function* fetchMonitorOverviewEffect() { ) ); } + +export const TRENDS_CHUNK_SIZE = 50; + +export function* fetchTrendEffect( + action: ReturnType +): Generator { + try { + // batch requests LIFO as the user scrolls + for (let i = action.payload.length; i > 0; i -= TRENDS_CHUNK_SIZE) { + const chunk = action.payload.slice(Math.max(i - TRENDS_CHUNK_SIZE, 0), i); + if (chunk.length > 0) { + const trendStats = yield call(trendsApi, chunk); + yield put(trendStatsBatch.success(trendStats)); + } + } + } catch (e: any) { + yield put(trendStatsBatch.fail(e)); + } +} + +export function* fetchOverviewTrendStats() { + yield takeEvery(trendStatsBatch.get, fetchTrendEffect); +} + +export function* refreshTrends(): Generator { + const existingTrends: TrendTable = yield select(selectOverviewTrends); + const overviewState: MonitorOverviewState = yield select(selectOverviewState); + + let acc = {}; + const keys = Object.keys(existingTrends); + while (keys.length) { + const chunk = keys + .splice(0, keys.length < 10 ? keys.length : 40) + .filter( + (key: string) => + existingTrends[key] !== null && + overviewState.data.monitors.some( + ({ configId }) => configId === existingTrends[key]!.configId + ) + ) + .map((key: string) => ({ + configId: existingTrends[key]!.configId, + locationId: existingTrends[key]!.locationId, + schedule: overviewState.data.monitors.find( + ({ configId }) => configId === existingTrends[key]!.configId + )!.schedule, + })); + if (chunk.length) { + const res = yield call(trendsApi, chunk); + acc = { ...acc, ...res }; + } + } + if (Object.keys(acc).length) { + yield put(trendStatsBatch.success(acc)); + } +} + +export function* refreshOverviewTrendStats() { + yield takeLeading(refreshOverviewTrends.get, refreshTrends); +} diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/index.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/index.ts index 665a92aeaf773..74ad8bb7a2a57 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/index.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/index.ts @@ -16,6 +16,7 @@ import { setOverviewGroupByAction, setOverviewPageStateAction, toggleErrorPopoverOpen, + trendStatsBatch, } from './actions'; import { enableMonitorAlertAction } from '../monitor_list/actions'; import { ConfigKey } from '../../components/monitor_add_edit/types'; @@ -31,6 +32,7 @@ const initialState: MonitorOverviewState = { sortOrder: 'asc', sortField: 'status', }, + trendStats: {}, groupBy: { field: 'none', order: 'asc' }, flyoutConfig: null, loading: false, @@ -93,6 +95,18 @@ export const monitorOverviewReducer = createReducer(initialState, (builder) => { }) .addCase(toggleErrorPopoverOpen, (state, action) => { state.isErrorPopoverOpen = action.payload; + }) + .addCase(trendStatsBatch.get, (state, action) => { + for (const { configId, locationId } of action.payload) { + if (!state.trendStats[configId + locationId]) { + state.trendStats[configId + locationId] = null; + } + } + }) + .addCase(trendStatsBatch.success, (state, action) => { + for (const key of Object.keys(action.payload)) { + state.trendStats[key] = action.payload[key]; + } }); }); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/models.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/models.ts index 8706ca519d49f..0dbc2100c2fee 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/models.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/models.ts @@ -4,6 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + +import type { TrendTable } from '../../../../../common/types'; import type { MonitorListSortField } from '../../../../../common/runtime_types/monitor_management/sort_field'; import { ConfigKey, MonitorOverviewResult } from '../../../../../common/runtime_types'; @@ -32,6 +34,7 @@ export interface MonitorOverviewState { isErrorPopoverOpen?: string | null; error: IHttpSerializedFetchError | null; groupBy: GroupByState; + trendStats: TrendTable; } export interface GroupByState { diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/selectors.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/selectors.ts index 677b7cc8208d9..98286a3da118f 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/selectors.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/selectors.ts @@ -16,3 +16,7 @@ export const selectErrorPopoverState = createSelector( selectOverviewState, (state) => state.isErrorPopoverOpen ); +export const selectOverviewTrends = createSelector( + selectOverviewState, + ({ trendStats }) => trendStats +); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_effect.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_effect.ts index 62d671d8e98fd..424c6fa70eed6 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_effect.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_effect.ts @@ -33,7 +33,11 @@ import { upsertMonitorEffect, fetchMonitorFiltersEffect, } from './monitor_list'; -import { fetchMonitorOverviewEffect } from './overview'; +import { + fetchMonitorOverviewEffect, + fetchOverviewTrendStats, + refreshOverviewTrendStats, +} from './overview'; import { fetchServiceLocationsEffect } from './service_locations'; import { browserJourneyEffects, fetchJourneyStepsEffect } from './browser_journey'; import { fetchPingStatusesEffect } from './ping_status'; @@ -71,5 +75,7 @@ export const rootEffect = function* root(): Generator { fork(getCertsListEffect), fork(getDefaultAlertingEffect), fork(enableDefaultAlertingSilentlyEffect), + fork(fetchOverviewTrendStats), + fork(refreshOverviewTrendStats), ]); }; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/utils/testing/__mocks__/synthetics_store.mock.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/utils/testing/__mocks__/synthetics_store.mock.ts index abfc08919b33a..897be8c4ad970 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/utils/testing/__mocks__/synthetics_store.mock.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/utils/testing/__mocks__/synthetics_store.mock.ts @@ -100,6 +100,7 @@ export const mockState: SyntheticsAppState = { sortOrder: 'asc', sortField: 'name.keyword', }, + trendStats: {}, data: { total: 0, allMonitorIds: [], diff --git a/x-pack/plugins/observability_solution/synthetics/server/lib.ts b/x-pack/plugins/observability_solution/synthetics/server/lib.ts index 12f08d679c89e..63d511a2d2063 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/lib.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/lib.ts @@ -122,8 +122,8 @@ export class SyntheticsEsClient { } async msearch< - TDocument = unknown, - TSearchRequest extends estypes.SearchRequest = estypes.SearchRequest + TSearchRequest extends estypes.SearchRequest = estypes.SearchRequest, + TDocument = unknown >( requests: MsearchMultisearchBody[] ): Promise<{ responses: Array> }> { diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/index.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/index.ts index c97abe44a6c5a..ba3bc0b443fb9 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/index.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/index.ts @@ -60,6 +60,7 @@ import { getAllSyntheticsMonitorRoute } from './monitor_cruds/get_monitors_list' import { getLocationMonitors } from './settings/private_locations/get_location_monitors'; import { addSyntheticsParamsRoute } from './settings/params/add_param'; import { deleteSyntheticsParamsRoute } from './settings/params/delete_param'; +import { createOverviewTrendsRoute } from './overview_trends/overview_trends'; export const syntheticsAppRestApiRoutes: SyntheticsRestApiRouteFactory[] = [ addSyntheticsProjectMonitorRoute, @@ -101,6 +102,7 @@ export const syntheticsAppRestApiRoutes: SyntheticsRestApiRouteFactory[] = [ getConnectorTypesRoute, createGetDynamicSettingsRoute, createPostDynamicSettingsRoute, + createOverviewTrendsRoute, ]; export const syntheticsAppPublicRestApiRoutes: SyntheticsRestApiRouteFactory[] = [ diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/overview_trends/fetch_trends.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/overview_trends/fetch_trends.ts new file mode 100644 index 0000000000000..b57c634c1bddd --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/overview_trends/fetch_trends.ts @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EXCLUDE_RUN_ONCE_FILTER, SUMMARY_FILTER } from '../../../common/constants/client_defaults'; +import { createEsParams } from '../../lib'; + +export const getFetchTrendsQuery = (configId: string, locationIds: string[], interval: number) => + createEsParams({ + body: { + size: 0, + query: { + bool: { + filter: [ + SUMMARY_FILTER, + EXCLUDE_RUN_ONCE_FILTER, + { + terms: { + 'observer.name': locationIds, + }, + }, + { + term: { + config_id: configId, + }, + }, + { + range: { + '@timestamp': { + gte: `now-${interval}m`, + lte: 'now', + }, + }, + }, + ], + }, + }, + aggs: { + byId: { + terms: { + field: 'config_id', + }, + aggs: { + byLocation: { + terms: { + field: 'observer.name', + }, + aggs: { + last50: { + histogram: { + field: '@timestamp', + interval: interval * 1000, + min_doc_count: 1, + }, + aggs: { + max: { + avg: { + field: 'monitor.duration.us', + }, + }, + }, + }, + stats: { + stats: { + field: 'monitor.duration.us', + }, + }, + median: { + percentiles: { + field: 'monitor.duration.us', + percents: [50], + }, + }, + }, + }, + }, + }, + }, + _source: false, + sort: [ + { + '@timestamp': 'desc', + }, + ], + fields: ['monitor.duration.us'], + }, + }); + +export type TrendsQuery = ReturnType; diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/overview_trends/overview_trends.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/overview_trends/overview_trends.ts new file mode 100644 index 0000000000000..e3d7589160c02 --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/overview_trends/overview_trends.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ObjectType, schema } from '@kbn/config-schema'; +import { SYNTHETICS_API_URLS } from '../../../common/constants'; +import { TrendRequest, TrendTable } from '../../../common/types'; +import { getFetchTrendsQuery, TrendsQuery } from './fetch_trends'; +import { SyntheticsRestApiRouteFactory } from '../types'; + +export const getIntervalForCheckCount = (schedule: string, numChecks = 50) => + Number(schedule) * numChecks; + +export const createOverviewTrendsRoute: SyntheticsRestApiRouteFactory = () => ({ + method: 'POST', + path: SYNTHETICS_API_URLS.OVERVIEW_TRENDS, + validate: { + body: schema.arrayOf( + schema.object({ + configId: schema.string(), + locationId: schema.string(), + schedule: schema.string(), + }) + ) as unknown as ObjectType, + }, + handler: async (routeContext): Promise => { + const esClient = routeContext.syntheticsEsClient; + const body = routeContext.request.body as TrendRequest[]; + + const configs = body.reduce( + ( + acc: Record, + { configId, locationId, schedule } + ) => { + if (!acc[configId]) { + acc[configId] = { locations: [locationId], interval: getIntervalForCheckCount(schedule) }; + } else { + acc[configId].locations.push(locationId); + } + return acc; + }, + {} + ); + + const requests = Object.keys(configs).map( + (key) => getFetchTrendsQuery(key, configs[key].locations, configs[key].interval).body + ); + const results = await esClient.msearch(requests); + + let main = {}; + for (const res of results.responses) { + res.aggregations?.byId.buckets.map(({ key, byLocation }) => { + const ret: Record = {}; + for (const location of byLocation.buckets) { + ret[String(key) + String(location.key)] = { + configId: key, + locationId: location.key, + data: location.last50.buckets.map((durationBucket, x) => ({ + x, + y: durationBucket.max.value, + })), + ...location.stats, + median: location.median.values['50.0'], + }; + } + main = { ...main, ...ret }; + }); + } + return main; + }, +}); diff --git a/yarn.lock b/yarn.lock index 383addbf0098b..dc184796bc241 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11174,7 +11174,15 @@ "@types/prop-types" "*" "@types/react" "*" -"@types/react-window@^1.8.8": +"@types/react-window-infinite-loader@^1.0.9": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@types/react-window-infinite-loader/-/react-window-infinite-loader-1.0.9.tgz#9b24d4e60f20397ff853c6857f7fe0645becbeb9" + integrity sha512-gEInTjQwURCnDOFyIEK2+fWB5gTjqwx30O62QfxA9stE5aiB6EWkGj4UMhc0axq7/FV++Gs/TGW8FtgEx0S6Tw== + dependencies: + "@types/react" "*" + "@types/react-window" "*" + +"@types/react-window@*", "@types/react-window@^1.8.8": version "1.8.8" resolved "https://registry.yarnpkg.com/@types/react-window/-/react-window-1.8.8.tgz#c20645414d142364fbe735818e1c1e0a145696e3" integrity sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q== @@ -26949,6 +26957,11 @@ react-virtualized@^9.22.5: prop-types "^15.7.2" react-lifecycles-compat "^3.0.4" +react-window-infinite-loader@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/react-window-infinite-loader/-/react-window-infinite-loader-1.0.9.tgz#d861c03d5cbc550e2f185371af820fd22d46c099" + integrity sha512-5Hg89IdU4Vrp0RT8kZYKeTIxWZYhNkVXeI1HbKo01Vm/Z7qztDvXljwx16sMzsa9yapRJQW3ODZfMUw38SOWHw== + react-window@^1.8.10: version "1.8.10" resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.10.tgz#9e6b08548316814b443f7002b1cf8fd3a1bdde03" @@ -27212,6 +27225,11 @@ redux-devtools-extension@^2.13.8: resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz#37b982688626e5e4993ff87220c9bbb7cd2d96e1" integrity sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg== +redux-saga-testing@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/redux-saga-testing/-/redux-saga-testing-2.0.2.tgz#a542b771a6b6584397198f35d47d07bae8dbfc9c" + integrity sha512-8IVPTaEw0Typ9TGCAsktFrrU+I5ACbmwPmzW0DQjUgZvja0k1jP2ILnUn+fZDF1gT8c0L/Ubj//bsej5X3OkaQ== + redux-saga@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/redux-saga/-/redux-saga-1.1.3.tgz#9f3e6aebd3c994bbc0f6901a625f9a42b51d1112" From 172293742b90c06e97d76e7f6e360421b773d5a4 Mon Sep 17 00:00:00 2001 From: Jon Date: Wed, 4 Sep 2024 15:36:31 -0500 Subject: [PATCH 06/99] [build] Use wolfi as the base for cloud image (#190847) --- .../build/tasks/os_packages/create_os_package_tasks.ts | 6 +++--- src/dev/build/tasks/os_packages/docker_generator/run.ts | 2 +- .../docker_generator/templates/base/Dockerfile | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/dev/build/tasks/os_packages/create_os_package_tasks.ts b/src/dev/build/tasks/os_packages/create_os_package_tasks.ts index 1a3708a3d5bcd..5233ca6ce481a 100644 --- a/src/dev/build/tasks/os_packages/create_os_package_tasks.ts +++ b/src/dev/build/tasks/os_packages/create_os_package_tasks.ts @@ -147,14 +147,14 @@ export const CreateDockerCloud: Task = { async run(config, log, build) { await runDockerGenerator(config, log, build, { architecture: 'x64', - baseImage: 'ubuntu', + baseImage: 'wolfi', context: false, cloud: true, image: true, }); await runDockerGenerator(config, log, build, { architecture: 'aarch64', - baseImage: 'ubuntu', + baseImage: 'wolfi', context: false, cloud: true, image: true, @@ -204,7 +204,7 @@ export const CreateDockerContexts: Task = { image: false, }); await runDockerGenerator(config, log, build, { - baseImage: 'ubuntu', + baseImage: 'wolfi', cloud: true, context: true, image: false, diff --git a/src/dev/build/tasks/os_packages/docker_generator/run.ts b/src/dev/build/tasks/os_packages/docker_generator/run.ts index 46225c5266048..1d0e81526e9ba 100644 --- a/src/dev/build/tasks/os_packages/docker_generator/run.ts +++ b/src/dev/build/tasks/os_packages/docker_generator/run.ts @@ -54,7 +54,7 @@ export async function runDockerGenerator( let imageFlavor = ''; if (flags.baseImage === 'ubi') imageFlavor += `-ubi`; - if (flags.baseImage === 'wolfi' && !flags.serverless) imageFlavor += `-wolfi`; + if (flags.baseImage === 'wolfi' && !flags.serverless && !flags.cloud) imageFlavor += `-wolfi`; if (flags.ironbank) imageFlavor += '-ironbank'; if (flags.cloud) imageFlavor += '-cloud'; if (flags.serverless) imageFlavor += '-serverless'; diff --git a/src/dev/build/tasks/os_packages/docker_generator/templates/base/Dockerfile b/src/dev/build/tasks/os_packages/docker_generator/templates/base/Dockerfile index acd5b54a74f1b..ec5588b4c793e 100644 --- a/src/dev/build/tasks/os_packages/docker_generator/templates/base/Dockerfile +++ b/src/dev/build/tasks/os_packages/docker_generator/templates/base/Dockerfile @@ -134,7 +134,7 @@ RUN for iter in {1..10}; do \ (exit $exit_code) {{/ubuntu}} {{#wolfi}} -RUN apk --no-cache add bash curl fontconfig libstdc++ nss findutils shadow +RUN apk --no-cache add bash curl fontconfig libstdc++ libnss findutils shadow {{/wolfi}} # Bring in Kibana from the initial stage. @@ -152,8 +152,8 @@ WORKDIR /usr/share/kibana {{#fips}} # Enable FIPS for Kibana only. In the future we can override OS wide with ENV OPENSSL_CONF -RUN /usr/bin/echo -e '\n--enable-fips' >> config/node.options -RUN /usr/bin/echo '--openssl-config=/usr/share/kibana/config/nodejs.cnf' >> config/node.options +RUN /bin/echo -e '\n--enable-fips' >> config/node.options +RUN echo '--openssl-config=/usr/share/kibana/config/nodejs.cnf' >> config/node.options COPY --chown=1000:0 openssl/nodejs.cnf "/usr/share/kibana/config/nodejs.cnf" ENV OPENSSL_MODULES=/usr/share/kibana/openssl/lib/ossl-modules ENV XPACK_SECURITY_EXPERIMENTAL_FIPSMODE_ENABLED=true @@ -231,7 +231,7 @@ ENTRYPOINT ["/bin/tini", "--"] CMD ["/app/kibana.sh"] # Generate a stub command that will be overwritten at runtime RUN mkdir /app && \ - /usr/bin/echo -e '#!/bin/bash\nexec /usr/local/bin/kibana-docker' > /app/kibana.sh && \ + /bin/echo -e '#!/bin/bash\nexec /usr/local/bin/kibana-docker' > /app/kibana.sh && \ chmod 0555 /app/kibana.sh {{/cloud}} From 221f8c0bea751696bc22e8564f4919c8b0ab2941 Mon Sep 17 00:00:00 2001 From: "elastic-renovate-prod[bot]" <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:39:46 -0500 Subject: [PATCH 07/99] Update dependency msw to ^2.4.0 (main) (#191700) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [msw](https://mswjs.io) ([source](https://togithub.com/mswjs/msw)) | devDependencies | minor | [`^2.3.5` -> `^2.4.0`](https://renovatebot.com/diffs/npm/msw/2.3.5/2.4.0) | --- ### Release Notes
mswjs/msw (msw) ### [`v2.4.0`](https://togithub.com/mswjs/msw/releases/tag/v2.4.0) [Compare Source](https://togithub.com/mswjs/msw/compare/v2.3.5...v2.4.0) #### v2.4.0 (2024-08-28) ##### Features - add `HttpResponse.html()` static method ([#​2140](https://togithub.com/mswjs/msw/issues/2140), [docs](https://mswjs.io/docs/api/http-response#httpresponsehtmlbody-init)) ([`8c5580a`](https://togithub.com/mswjs/msw/commit/8c5580a0e2e6e52785b0132128c36d679ddbe5d5)) [@​scruffymongrel](https://togithub.com/scruffymongrel) [@​kettanaito](https://togithub.com/kettanaito) - list "graphql" as an optional peer dependency ([#​2187](https://togithub.com/mswjs/msw/issues/2187)) ([`40b17fd`](https://togithub.com/mswjs/msw/commit/40b17fdf655e597b352094527f558f6d839f2970)) [@​kettanaito](https://togithub.com/kettanaito) - print request body in `onUnhandledRequest` message ([#​2227](https://togithub.com/mswjs/msw/issues/2227)) ([`a2153c9`](https://togithub.com/mswjs/msw/commit/a2153c93edd752d7c5686573f684721b19f0a115)) [@​bitttttten](https://togithub.com/bitttttten) [@​kettanaito](https://togithub.com/kettanaito)
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://togithub.com/renovatebot/renovate). Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 552b585167337..bd651820800ce 100644 --- a/package.json +++ b/package.json @@ -1744,7 +1744,7 @@ "mochawesome-merge": "^4.3.0", "mock-fs": "^5.1.2", "ms-chromium-edge-driver": "^0.5.1", - "msw": "^2.3.5", + "msw": "^2.4.1", "multistream": "^4.1.0", "mutation-observer": "^1.0.3", "native-hdr-histogram": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index dc184796bc241..6326e9d409ca7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19097,7 +19097,7 @@ graphql-tag@^2.12.6: dependencies: tslib "^2.1.0" -graphql@^16.6.0, graphql@^16.8.1: +graphql@^16.6.0: version "16.8.1" resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.1.tgz#1930a965bef1170603702acdb68aedd3f3cf6f07" integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw== @@ -23701,10 +23701,10 @@ msgpackr@^1.9.9: optionalDependencies: msgpackr-extract "^3.0.2" -msw@^2.3.5: - version "2.3.5" - resolved "https://registry.yarnpkg.com/msw/-/msw-2.3.5.tgz#424ad91b20a548d6b77fc26aca0c789e5cbc4764" - integrity sha512-+GUI4gX5YC5Bv33epBrD+BGdmDvBg2XGruiWnI3GbIbRmMMBeZ5gs3mJ51OWSGHgJKztZ8AtZeYMMNMVrje2/Q== +msw@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/msw/-/msw-2.4.1.tgz#bb0ead0311de39d5847ff0836b9dd67e7bba02b8" + integrity sha512-HXcoQPzYTwEmVk+BGIcRa0vLabBT+J20SSSeYh/QfajaK5ceA6dlD4ZZjfz2dqGEq4vRNCPLP6eXsB94KllPFg== dependencies: "@bundled-es-modules/cookie" "^2.0.0" "@bundled-es-modules/statuses" "^1.0.1" @@ -23715,7 +23715,6 @@ msw@^2.3.5: "@types/cookie" "^0.6.0" "@types/statuses" "^2.0.4" chalk "^4.1.2" - graphql "^16.8.1" headers-polyfill "^4.0.2" is-node-process "^1.2.0" outvariant "^1.4.2" From 30b23330677bafe41839e9d4bb158084fb2126ab Mon Sep 17 00:00:00 2001 From: "elastic-renovate-prod[bot]" <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:15:52 -0500 Subject: [PATCH 08/99] Update dependency msw to ^2.4.2 (main) (#192139) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [msw](https://mswjs.io) ([source](https://togithub.com/mswjs/msw)) | devDependencies | patch | [`^2.4.1` -> `^2.4.2`](https://renovatebot.com/diffs/npm/msw/2.4.1/2.4.2) | --- ### Release Notes
mswjs/msw (msw) ### [`v2.4.2`](https://togithub.com/mswjs/msw/releases/tag/v2.4.2) [Compare Source](https://togithub.com/mswjs/msw/compare/v2.4.1...v2.4.2) #### v2.4.2 (2024-09-04) ##### Bug Fixes - **cli:** support windows paths in the `init` command ([#​2260](https://togithub.com/mswjs/msw/issues/2260)) ([`ba285b8`](https://togithub.com/mswjs/msw/commit/ba285b887cedfa22f32ae1e8d6569e57174cb561)) [@​ivanfernandez2646](https://togithub.com/ivanfernandez2646) [@​kettanaito](https://togithub.com/kettanaito) - use typescript@4.8 as the minimal supported version ([#​2251](https://togithub.com/mswjs/msw/issues/2251)) ([`6b2a7e6`](https://togithub.com/mswjs/msw/commit/6b2a7e6be8f9b63c2549ad7fbf271d38f803ad6e)) [@​THETCR](https://togithub.com/THETCR) [@​kettanaito](https://togithub.com/kettanaito) - keep `graphql` import as require in cjs ([#​2258](https://togithub.com/mswjs/msw/issues/2258)) ([`b977602`](https://togithub.com/mswjs/msw/commit/b97760270b28bd633b56332d87a9d834f653cad2)) [@​kettanaito](https://togithub.com/kettanaito)
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://togithub.com/renovatebot/renovate). Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index bd651820800ce..51a16ffbefe18 100644 --- a/package.json +++ b/package.json @@ -1744,7 +1744,7 @@ "mochawesome-merge": "^4.3.0", "mock-fs": "^5.1.2", "ms-chromium-edge-driver": "^0.5.1", - "msw": "^2.4.1", + "msw": "^2.4.2", "multistream": "^4.1.0", "mutation-observer": "^1.0.3", "native-hdr-histogram": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index 6326e9d409ca7..b4de9715dcf10 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23701,10 +23701,10 @@ msgpackr@^1.9.9: optionalDependencies: msgpackr-extract "^3.0.2" -msw@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/msw/-/msw-2.4.1.tgz#bb0ead0311de39d5847ff0836b9dd67e7bba02b8" - integrity sha512-HXcoQPzYTwEmVk+BGIcRa0vLabBT+J20SSSeYh/QfajaK5ceA6dlD4ZZjfz2dqGEq4vRNCPLP6eXsB94KllPFg== +msw@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/msw/-/msw-2.4.2.tgz#df8040975b2bf92ebc0a16d1c9e9f138c3c8765c" + integrity sha512-GImSQGhn19czhVpxPdiUDK8CMZ6jbBcvOhzfJd8KFErjEER2wDKWs1UYaetJs2GSNlAqt6heZYm7g3eLatTcog== dependencies: "@bundled-es-modules/cookie" "^2.0.0" "@bundled-es-modules/statuses" "^1.0.1" From 86cfcab8770a5b31e73c179baad53ee382c837f4 Mon Sep 17 00:00:00 2001 From: Matthew Kime Date: Wed, 4 Sep 2024 18:36:35 -0500 Subject: [PATCH 09/99] [data views / hasData] Check resolve cluster instead of resolve index for improved performance (#191566) ## Summary The `resolve/cluster` api is MUCH more efficient for determining whether there are user created indices than the `resolve/index` api. The `resolve/index` api returns the FULL list of indices which can be very large. Unfortunately the `resolve/cluster` api isn't available on serverless so we rely on the existing `hasESData` behavior when its not available. Closes https://github.com/elastic/kibana/issues/190554 Created https://github.com/elastic/elasticsearch/issues/112307 in hopes of getting an api thats performant in serverless and classic environments. Additional detail - `logs-enterprise_search.api-default` and `logs-enterprise_search.audit-default` should be ignored for the purposes of user created data. --- Testing - verify the loading data flows display as appropriate for discover and data view management. Create and delete indices. ## Release notes In deployments with thousands of indices and index aliases, browser calls to `/internal/index-pattern-management/resolve_index` can be very slow (more than 10s). Its been replaced with `/internal/data_views/has_es_data` which is much faster (<1s). --------- Co-authored-by: Davis McPhee --- src/plugins/data_views/public/plugin.ts | 7 +- .../public/services/has_data.test.ts | 463 ++++++++++-------- .../data_views/public/services/has_data.ts | 36 +- .../rest_api_routes/internal/has_es_data.ts | 58 +++ src/plugins/data_views/server/routes.ts | 2 + 5 files changed, 350 insertions(+), 216 deletions(-) create mode 100644 src/plugins/data_views/server/rest_api_routes/internal/has_es_data.ts diff --git a/src/plugins/data_views/public/plugin.ts b/src/plugins/data_views/public/plugin.ts index 3a847ce939981..3cdf2428bf389 100644 --- a/src/plugins/data_views/public/plugin.ts +++ b/src/plugins/data_views/public/plugin.ts @@ -41,8 +41,11 @@ export class DataViewsPublicPlugin { private readonly hasData = new HasData(); private rollupsEnabled: boolean = false; + private readonly callResolveCluster: boolean; - constructor(private readonly initializerContext: PluginInitializerContext) {} + constructor(private readonly initializerContext: PluginInitializerContext) { + this.callResolveCluster = initializerContext.env.packageInfo.buildFlavor === 'traditional'; + } public setup( core: CoreSetup, @@ -83,7 +86,7 @@ export class DataViewsPublicPlugin const config = this.initializerContext.config.get(); return new DataViewsServicePublic({ - hasData: this.hasData.start(core), + hasData: this.hasData.start(core, this.callResolveCluster), uiSettings: new UiSettingsPublicToCommon(uiSettings), savedObjectsClient: new ContentMagementWrapper(contentManagement.client), apiClient: new DataViewsApiClient(http, async () => { diff --git a/src/plugins/data_views/public/services/has_data.test.ts b/src/plugins/data_views/public/services/has_data.test.ts index b2ccf3828af6b..7118aa5cceaf5 100644 --- a/src/plugins/data_views/public/services/has_data.test.ts +++ b/src/plugins/data_views/public/services/has_data.test.ts @@ -11,241 +11,288 @@ import { coreMock } from '@kbn/core/public/mocks'; import { HasData } from './has_data'; describe('when calling hasData service', () => { - it('should return true for hasESData when indices exist', async () => { - const coreStart = coreMock.createStart(); - const http = coreStart.http; - - // Mock getIndices - const spy = jest.spyOn(http, 'get').mockImplementation(() => - Promise.resolve({ - aliases: [], - data_streams: [], - indices: [ - { - aliases: [], - attributes: ['open'], - name: 'sample_data_logs', - }, - ], - }) - ); - - const hasData = new HasData(); - const hasDataService = hasData.start(coreStart); - const response = hasDataService.hasESData(); - - expect(spy).toHaveBeenCalledTimes(1); - - expect(await response).toBe(true); - }); - - it('should return false for hasESData when no indices exist', async () => { - const coreStart = coreMock.createStart(); - const http = coreStart.http; - - // Mock getIndices - const spy = jest.spyOn(http, 'get').mockImplementation(() => - Promise.resolve({ - aliases: [], - data_streams: [], - indices: [], - }) - ); - - const hasData = new HasData(); - const hasDataService = hasData.start(coreStart); - const response = hasDataService.hasESData(); - - expect(spy).toHaveBeenCalledTimes(1); - - expect(await response).toBe(false); - }); - - it('should return false for hasESData when only automatically created sources exist', async () => { - const coreStart = coreMock.createStart(); - const http = coreStart.http; - - // Mock getIndices - const spy = jest.spyOn(http, 'get').mockImplementation((path: any) => - Promise.resolve({ - aliases: [], - data_streams: path.includes('*:*') - ? [] // return empty on remote cluster call - : [ - { - name: 'logs-enterprise_search.api-default', - timestamp_field: '@timestamp', - backing_indices: ['.ds-logs-enterprise_search.api-default-2022.03.07-000001'], - }, - ], - indices: [], - }) - ); - - const hasData = new HasData(); - const hasDataService = hasData.start(coreStart); - const response = hasDataService.hasESData(); - - expect(spy).toHaveBeenCalledTimes(1); - - expect(await response).toBe(false); - }); - - it('should hit search api in case resolve api throws', async () => { - const coreStart = coreMock.createStart(); - const http = coreStart.http; - - const spyGetIndices = jest - .spyOn(http, 'get') - .mockImplementation(() => Promise.reject(new Error('oops'))); - - const spySearch = jest - .spyOn(http, 'post') - .mockImplementation(() => Promise.resolve({ total: 10 })); - const hasData = new HasData(); - const hasDataService = hasData.start(coreStart); - const response = await hasDataService.hasESData(); + describe('hasDataView', () => { + it('should return true for hasDataView when server returns true', async () => { + const coreStart = coreMock.createStart(); + const http = coreStart.http; + + // Mock getIndices + const spy = jest.spyOn(http, 'get').mockImplementation(() => + Promise.resolve({ + hasDataView: true, + hasUserDataView: true, + }) + ); + + const hasData = new HasData(); + const hasDataService = hasData.start(coreStart, true); + const response = hasDataService.hasDataView(); + + expect(spy).toHaveBeenCalledTimes(1); - expect(response).toBe(true); + expect(await response).toBe(true); + }); + + it('should return false for hasDataView when server returns false', async () => { + const coreStart = coreMock.createStart(); + const http = coreStart.http; + + // Mock getIndices + const spy = jest.spyOn(http, 'get').mockImplementation(() => + Promise.resolve({ + hasDataView: false, + hasUserDataView: true, + }) + ); + + const hasData = new HasData(); + const hasDataService = hasData.start(coreStart, true); + const response = hasDataService.hasDataView(); + + expect(spy).toHaveBeenCalledTimes(1); + + expect(await response).toBe(false); + }); + + it('should return true for hasDataView when server throws an error', async () => { + const coreStart = coreMock.createStart(); + const http = coreStart.http; + + // Mock getIndices + const spy = jest + .spyOn(http, 'get') + .mockImplementation(() => Promise.reject(new Error('Oops'))); + + const hasData = new HasData(); + const hasDataService = hasData.start(coreStart, true); + const response = hasDataService.hasDataView(); + + expect(spy).toHaveBeenCalledTimes(1); + + expect(await response).toBe(true); + }); + + it('should return false for hasUserDataView when server returns false', async () => { + const coreStart = coreMock.createStart(); + const http = coreStart.http; + + // Mock getIndices + const spy = jest.spyOn(http, 'get').mockImplementation(() => + Promise.resolve({ + hasDataView: true, + hasUserDataView: false, + }) + ); + + const hasData = new HasData(); + const hasDataService = hasData.start(coreStart, true); + const response = hasDataService.hasUserDataView(); + + expect(spy).toHaveBeenCalledTimes(1); + + expect(await response).toBe(false); + }); + + it('should return true for hasUserDataView when server returns true', async () => { + const coreStart = coreMock.createStart(); + const http = coreStart.http; + + // Mock getIndices + const spy = jest.spyOn(http, 'get').mockImplementation(() => + Promise.resolve({ + hasDataView: true, + hasUserDataView: true, + }) + ); + + const hasData = new HasData(); + const hasDataService = hasData.start(coreStart, true); + const response = hasDataService.hasUserDataView(); + + expect(spy).toHaveBeenCalledTimes(1); + + expect(await response).toBe(true); + }); - expect(spyGetIndices).toHaveBeenCalledTimes(1); - expect(spySearch).toHaveBeenCalledTimes(1); - }); - - it('should return false in case search api throws', async () => { - const coreStart = coreMock.createStart(); - const http = coreStart.http; + it('should return true for hasUserDataView when server throws an error', async () => { + const coreStart = coreMock.createStart(); + const http = coreStart.http; - const spyGetIndices = jest - .spyOn(http, 'get') - .mockImplementation(() => Promise.reject(new Error('oops'))); + // Mock getIndices + const spy = jest + .spyOn(http, 'get') + .mockImplementation(() => Promise.reject(new Error('Oops'))); - const spySearch = jest - .spyOn(http, 'post') - .mockImplementation(() => Promise.reject(new Error('oops'))); - const hasData = new HasData(); - const hasDataService = hasData.start(coreStart); - const response = await hasDataService.hasESData(); + const hasData = new HasData(); + const hasDataService = hasData.start(coreStart, true); + const response = hasDataService.hasUserDataView(); - expect(response).toBe(true); + expect(spy).toHaveBeenCalledTimes(1); - expect(spyGetIndices).toHaveBeenCalledTimes(1); - expect(spySearch).toHaveBeenCalledTimes(1); + expect(await response).toBe(true); + }); }); + describe('hasESData', () => { + describe('resolve/cluster is available', () => { + it('should return true for hasESData when indices exist', async () => { + const coreStart = coreMock.createStart(); + const http = coreStart.http; - it('should return true for hasDataView when server returns true', async () => { - const coreStart = coreMock.createStart(); - const http = coreStart.http; - - // Mock getIndices - const spy = jest.spyOn(http, 'get').mockImplementation(() => - Promise.resolve({ - hasDataView: true, - hasUserDataView: true, - }) - ); - - const hasData = new HasData(); - const hasDataService = hasData.start(coreStart); - const response = hasDataService.hasDataView(); - - expect(spy).toHaveBeenCalledTimes(1); - - expect(await response).toBe(true); - }); - - it('should return false for hasDataView when server returns false', async () => { - const coreStart = coreMock.createStart(); - const http = coreStart.http; - - // Mock getIndices - const spy = jest.spyOn(http, 'get').mockImplementation(() => - Promise.resolve({ - hasDataView: false, - hasUserDataView: true, - }) - ); - - const hasData = new HasData(); - const hasDataService = hasData.start(coreStart); - const response = hasDataService.hasDataView(); - - expect(spy).toHaveBeenCalledTimes(1); + // Mock getIndices + const spy = jest + .spyOn(http, 'get') + .mockImplementation(() => Promise.resolve({ hasEsData: true })); - expect(await response).toBe(false); - }); - - it('should return true for hasDataView when server throws an error', async () => { - const coreStart = coreMock.createStart(); - const http = coreStart.http; + const hasData = new HasData(); + const hasDataService = hasData.start(coreStart, true); + const response = hasDataService.hasESData(); - // Mock getIndices - const spy = jest.spyOn(http, 'get').mockImplementation(() => Promise.reject(new Error('Oops'))); + expect(spy).toHaveBeenCalledTimes(1); - const hasData = new HasData(); - const hasDataService = hasData.start(coreStart); - const response = hasDataService.hasDataView(); + expect(await response).toBe(true); + }); - expect(spy).toHaveBeenCalledTimes(1); + it('should return false for hasESData when no indices exist', async () => { + const coreStart = coreMock.createStart(); + const http = coreStart.http; - expect(await response).toBe(true); - }); + // Mock getIndices + const spy = jest + .spyOn(http, 'get') + .mockImplementation(() => Promise.resolve({ hasEsData: false })); - it('should return false for hasUserDataView when server returns false', async () => { - const coreStart = coreMock.createStart(); - const http = coreStart.http; + const hasData = new HasData(); + const hasDataService = hasData.start(coreStart, true); + const response = hasDataService.hasESData(); - // Mock getIndices - const spy = jest.spyOn(http, 'get').mockImplementation(() => - Promise.resolve({ - hasDataView: true, - hasUserDataView: false, - }) - ); + expect(spy).toHaveBeenCalledTimes(1); - const hasData = new HasData(); - const hasDataService = hasData.start(coreStart); - const response = hasDataService.hasUserDataView(); + expect(await response).toBe(false); + }); + }); - expect(spy).toHaveBeenCalledTimes(1); + describe('resolve/cluster not available', () => { + it('should return true for hasESData when indices exist', async () => { + const coreStart = coreMock.createStart(); + const http = coreStart.http; - expect(await response).toBe(false); - }); + // Mock getIndices + const spy = jest.spyOn(http, 'get').mockImplementationOnce(() => + Promise.resolve({ + aliases: [], + data_streams: [], + indices: [ + { + aliases: [], + attributes: ['open'], + name: 'sample_data_logs', + }, + ], + }) + ); - it('should return true for hasUserDataView when server returns true', async () => { - const coreStart = coreMock.createStart(); - const http = coreStart.http; + const hasData = new HasData(); + const hasDataService = hasData.start(coreStart, false); + const response = hasDataService.hasESData(); - // Mock getIndices - const spy = jest.spyOn(http, 'get').mockImplementation(() => - Promise.resolve({ - hasDataView: true, - hasUserDataView: true, - }) - ); + expect(spy).toHaveBeenCalledTimes(1); - const hasData = new HasData(); - const hasDataService = hasData.start(coreStart); - const response = hasDataService.hasUserDataView(); + expect(await response).toBe(true); + }); - expect(spy).toHaveBeenCalledTimes(1); + it('should return false for hasESData when no indices exist', async () => { + const coreStart = coreMock.createStart(); + const http = coreStart.http; - expect(await response).toBe(true); - }); + // Mock getIndices + const spy = jest.spyOn(http, 'get').mockImplementation(() => + Promise.resolve({ + aliases: [], + data_streams: [], + indices: [], + }) + ); - it('should return true for hasUserDataView when server throws an error', async () => { - const coreStart = coreMock.createStart(); - const http = coreStart.http; + const hasData = new HasData(); + const hasDataService = hasData.start(coreStart, false); + const response = hasDataService.hasESData(); - // Mock getIndices - const spy = jest.spyOn(http, 'get').mockImplementation(() => Promise.reject(new Error('Oops'))); + expect(spy).toHaveBeenCalledTimes(1); - const hasData = new HasData(); - const hasDataService = hasData.start(coreStart); - const response = hasDataService.hasUserDataView(); + expect(await response).toBe(false); + }); - expect(spy).toHaveBeenCalledTimes(1); + it('should return false for hasESData when only automatically created sources exist', async () => { + const coreStart = coreMock.createStart(); + const http = coreStart.http; - expect(await response).toBe(true); + // Mock getIndices + const spy = jest.spyOn(http, 'get').mockImplementation((path: any) => + Promise.resolve({ + aliases: [], + data_streams: path.includes('*:*') + ? [] // return empty on remote cluster call + : [ + { + name: 'logs-enterprise_search.api-default', + timestamp_field: '@timestamp', + backing_indices: ['.ds-logs-enterprise_search.api-default-2022.03.07-000001'], + }, + ], + indices: [], + }) + ); + + const hasData = new HasData(); + const hasDataService = hasData.start(coreStart, false); + const response = hasDataService.hasESData(); + + expect(spy).toHaveBeenCalledTimes(1); + + expect(await response).toBe(false); + }); + + it('should hit search api in case resolve api throws', async () => { + const coreStart = coreMock.createStart(); + const http = coreStart.http; + + const spyGetIndices = jest + .spyOn(http, 'get') + .mockImplementation(() => Promise.reject(new Error('oops'))); + + const spySearch = jest + .spyOn(http, 'post') + .mockImplementation(() => Promise.resolve({ total: 10 })); + const hasData = new HasData(); + const hasDataService = hasData.start(coreStart, false); + const response = await hasDataService.hasESData(); + + expect(response).toBe(true); + + expect(spyGetIndices).toHaveBeenCalledTimes(1); + expect(spySearch).toHaveBeenCalledTimes(1); + }); + + it('should return false in case search api throws', async () => { + const coreStart = coreMock.createStart(); + const http = coreStart.http; + + const spyGetIndices = jest + .spyOn(http, 'get') + .mockImplementation(() => Promise.reject(new Error('oops'))); + + const spySearch = jest + .spyOn(http, 'post') + .mockImplementation(() => Promise.reject(new Error('oops'))); + const hasData = new HasData(); + const hasDataService = hasData.start(coreStart, false); + const response = await hasDataService.hasESData(); + + expect(response).toBe(true); + + expect(spyGetIndices).toHaveBeenCalledTimes(1); + expect(spySearch).toHaveBeenCalledTimes(1); + }); + }); }); }); diff --git a/src/plugins/data_views/public/services/has_data.ts b/src/plugins/data_views/public/services/has_data.ts index 1e32825ec498b..a33e330bdb0ac 100644 --- a/src/plugins/data_views/public/services/has_data.ts +++ b/src/plugins/data_views/public/services/has_data.ts @@ -24,19 +24,43 @@ export class HasData { return true; }; - start(core: CoreStart) { + start(core: CoreStart, callResolveCluster: boolean) { const { http } = core; + + const hasESDataViaResolveIndex = async () => { + // fallback to previous implementation + const hasLocalESData = await this.checkLocalESData(http); + if (!hasLocalESData) { + const hasRemoteESData = await this.checkRemoteESData(http); + return hasRemoteESData; + } + return hasLocalESData; + }; + + const hasESDataViaResolveCluster = async () => { + try { + const { hasEsData } = await http.get<{ hasEsData: boolean }>( + '/internal/data_views/has_es_data', + { + version: '1', + } + ); + return hasEsData; + } catch (e) { + // fallback to previous implementation + return hasESDataViaResolveIndex(); + } + }; + return { /** * Check to see if ES data exists */ hasESData: async (): Promise => { - const hasLocalESData = await this.checkLocalESData(http); - if (!hasLocalESData) { - const hasRemoteESData = await this.checkRemoteESData(http); - return hasRemoteESData; + if (callResolveCluster) { + return hasESDataViaResolveCluster(); } - return hasLocalESData; + return hasESDataViaResolveIndex(); }, /** * Check to see if a data view exists diff --git a/src/plugins/data_views/server/rest_api_routes/internal/has_es_data.ts b/src/plugins/data_views/server/rest_api_routes/internal/has_es_data.ts new file mode 100644 index 0000000000000..6cd3e96ddfae6 --- /dev/null +++ b/src/plugins/data_views/server/rest_api_routes/internal/has_es_data.ts @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { IRouter, RequestHandlerContext } from '@kbn/core/server'; +import type { VersionedRoute } from '@kbn/core-http-server'; +import { schema } from '@kbn/config-schema'; +import { DEFAULT_ASSETS_TO_IGNORE } from '../../../common'; + +type Handler = Parameters['addVersion']>[1]; + +const patterns = ['*', '-.*'].concat( + DEFAULT_ASSETS_TO_IGNORE.DATA_STREAMS_TO_IGNORE.map((ds) => `-${ds}`) +); + +const crossClusterPatterns = patterns.map((ds) => `*:${ds}`); + +export const handler: Handler = async (ctx: RequestHandlerContext, req, res) => { + const core = await ctx.core; + const elasticsearchClient = core.elasticsearch.client.asCurrentUser; + const response = await elasticsearchClient.indices.resolveCluster({ + name: patterns.concat(crossClusterPatterns), + allow_no_indices: true, + ignore_unavailable: true, + }); + + const hasEsData = !!Object.values(response).find((cluster) => cluster.matching_indices); + + return res.ok({ body: { hasEsData } }); +}; + +export const registerHasEsDataRoute = (router: IRouter): void => { + router.versioned + .get({ + path: '/internal/data_views/has_es_data', + access: 'internal', + }) + .addVersion( + { + version: '1', + validate: { + response: { + 200: { + body: () => + schema.object({ + hasEsData: schema.boolean(), + }), + }, + }, + }, + }, + handler + ); +}; diff --git a/src/plugins/data_views/server/routes.ts b/src/plugins/data_views/server/routes.ts index d6ee36927ff80..54adfb0cf628d 100644 --- a/src/plugins/data_views/server/routes.ts +++ b/src/plugins/data_views/server/routes.ts @@ -14,6 +14,7 @@ import type { DataViewsServerPluginStart, DataViewsServerPluginStartDependencies import { registerExistingIndicesPath } from './rest_api_routes/internal/existing_indices'; import { registerFieldForWildcard } from './rest_api_routes/internal/fields_for'; import { registerHasDataViewsRoute } from './rest_api_routes/internal/has_data_views'; +import { registerHasEsDataRoute } from './rest_api_routes/internal/has_es_data'; import { registerFields } from './rest_api_routes/internal/fields'; interface RegisterRoutesArgs { @@ -40,4 +41,5 @@ export function registerRoutes({ registerFieldForWildcard(router, getStartServices, isRollupsEnabled); registerFields(router, getStartServices, isRollupsEnabled); registerHasDataViewsRoute(router); + registerHasEsDataRoute(router); } From 4710b0d84adb5679f10e7ecf8bc371b73f308b3a Mon Sep 17 00:00:00 2001 From: Brad White Date: Wed, 4 Sep 2024 17:52:03 -0600 Subject: [PATCH 10/99] [Docs] Clarify `.env` for Dev Container (#192142) ## Summary Adds a bit of clarification on where the dev container env configuration is located. --- dev_docs/getting_started/setting_up_a_development_env.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev_docs/getting_started/setting_up_a_development_env.mdx b/dev_docs/getting_started/setting_up_a_development_env.mdx index a63dfdce59b4d..b69987a09da50 100644 --- a/dev_docs/getting_started/setting_up_a_development_env.mdx +++ b/dev_docs/getting_started/setting_up_a_development_env.mdx @@ -99,7 +99,7 @@ Kibana also supports using a [dev container](https://containers.dev/) which can ### Setting up the Dev Container -1. Make a copy of `.devcontainer/.env.template` and rename it to `.devcontainer/.env`. Edit any values you're interested in. +1. Make a copy of [`/.devcontainer/.env.template`](https://github.com/elastic/kibana/blob/main/.devcontainer/.env.template) and rename it to `/.devcontainer/.env`. Edit any values you're interested in. 1. There are three options for mounting the Kibana repo into the container: - **Local Filesystem**: Clone the repo locally, or use an existing copy, and open it in VS Code. When prompted, select "Reopen in Dev Container". This uses a bind mount, allowing the container to access and modify files directly on your local filesystem. Your git credentials should be automatically mounted in the container as well. Note that Bazel will create symlinks and a cache inside the container file system. So, if switching to working on your local filesystem afterwards, you will need to bootstrap again. - **Docker Repo Volume**: Use the `Dev Containers: Clone Repository in Named Container Volume...` command from the Command Palette (`F1`). This clones the repo into a Docker volume, isolating it from your local filesystem. You will need to configure your git credentials manually in this isolated environment. From 80f920d4c511ceea68568bb9dd2dae13a024592b Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Thu, 5 Sep 2024 06:31:14 +0300 Subject: [PATCH 11/99] [Discover] Unskip context awareness tests (#192074) - Closes https://github.com/elastic/kibana/issues/191260 - Closes https://github.com/elastic/kibana/issues/190725 - Closes https://github.com/elastic/kibana/issues/190629 - Closes https://github.com/elastic/kibana/issues/191921 - Closes https://github.com/elastic/kibana/issues/189994 - Closes https://github.com/elastic/kibana/issues/192095 --- .../extensions/_get_cell_renderers.ts | 83 ++++++++++++++----- .../extensions/_get_default_app_state.ts | 19 +++-- .../extensions/_get_cell_renderers.ts | 83 ++++++++++++++----- .../extensions/_get_default_app_state.ts | 23 +++-- 4 files changed, 150 insertions(+), 58 deletions(-) diff --git a/test/functional/apps/discover/context_awareness/extensions/_get_cell_renderers.ts b/test/functional/apps/discover/context_awareness/extensions/_get_cell_renderers.ts index 0bd0523365d83..d290777c9008f 100644 --- a/test/functional/apps/discover/context_awareness/extensions/_get_cell_renderers.ts +++ b/test/functional/apps/discover/context_awareness/extensions/_get_cell_renderers.ts @@ -8,6 +8,7 @@ import kbnRison from '@kbn/rison'; import expect from '@kbn/expect'; +import type { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import type { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { @@ -18,6 +19,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const dataViews = getService('dataViews'); const queryBar = getService('queryBar'); const browser = getService('browser'); + const retry = getService('retry'); describe('extension getCellRenderers', () => { before(async () => { @@ -39,8 +41,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToActualUrl('discover', `?_a=${state}`, { ensureCurrentUrl: false, }); + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.discover.waitUntilSearchingHasFinished(); await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 0); const logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-'); expect(await logLevelBadge.getVisibleText()).to.be('debug'); @@ -59,11 +65,17 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToActualUrl('discover', `?_a=${state}`, { ensureCurrentUrl: false, }); + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.discover.waitUntilSearchingHasFinished(); await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); - const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 0); - expect(await firstCell.getVisibleText()).to.be('debug'); - await testSubjects.missingOrFail('*logLevelBadgeCell-'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + await retry.try(async () => { + const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 0); + expect(await firstCell.getVisibleText()).to.be('debug'); + await testSubjects.missingOrFail('*logLevelBadgeCell-'); + }); }); }); @@ -72,17 +84,28 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); - await dataViews.switchTo('my-example-logs,logstash*'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataViews.switchToAndValidate('my-example-logs,logstash*'); await queryBar.setQuery('log.level:*'); await queryBar.submitQuery(); + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.discover.waitUntilSearchingHasFinished(); await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); - let firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1); - let logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-'); - expect(await logLevelBadge.getVisibleText()).to.be('debug'); - expect(await logLevelBadge.getComputedStyle('background-color')).to.be( - 'rgba(190, 207, 227, 1)' - ); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + let firstCell: WebElementWrapper; + let logLevelBadge: WebElementWrapper; + + await retry.try(async () => { + firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1); + logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-'); + expect(await logLevelBadge.getVisibleText()).to.be('debug'); + expect(await logLevelBadge.getComputedStyle('background-color')).to.be( + 'rgba(190, 207, 227, 1)' + ); + }); // check Surrounding docs page await dataGrid.clickRowToggle(); @@ -92,26 +115,38 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await browser.refresh(); await PageObjects.header.waitUntilLoadingHasFinished(); - firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1); - logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-'); - expect(await logLevelBadge.getVisibleText()).to.be('debug'); - expect(await logLevelBadge.getComputedStyle('background-color')).to.be( - 'rgba(190, 207, 227, 1)' - ); + await retry.try(async () => { + firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1); + logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-'); + expect(await logLevelBadge.getVisibleText()).to.be('debug'); + expect(await logLevelBadge.getComputedStyle('background-color')).to.be( + 'rgba(190, 207, 227, 1)' + ); + }); }); it("should not render log.level badge cell if it's not a logs data source", async () => { await PageObjects.common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); - await dataViews.switchTo('my-example-*'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataViews.switchToAndValidate('my-example-*'); await queryBar.setQuery('log.level:*'); await queryBar.submitQuery(); + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.discover.waitUntilSearchingHasFinished(); await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); - let firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1); - expect(await firstCell.getVisibleText()).to.be('debug'); - await testSubjects.missingOrFail('*logLevelBadgeCell-'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + let firstCell: WebElementWrapper; + + await retry.try(async () => { + firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1); + expect(await firstCell.getVisibleText()).to.be('debug'); + await testSubjects.missingOrFail('*logLevelBadgeCell-'); + }); // check Surrounding docs page await dataGrid.clickRowToggle(); @@ -121,9 +156,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await browser.refresh(); await PageObjects.header.waitUntilLoadingHasFinished(); - firstCell = await dataGrid.getCellElementExcludingControlColumns(1, 1); - expect(await firstCell.getVisibleText()).to.be('debug'); - await testSubjects.missingOrFail('*logLevelBadgeCell-'); + await retry.try(async () => { + firstCell = await dataGrid.getCellElementExcludingControlColumns(1, 1); + expect(await firstCell.getVisibleText()).to.be('debug'); + await testSubjects.missingOrFail('*logLevelBadgeCell-'); + }); }); }); }); diff --git a/test/functional/apps/discover/context_awareness/extensions/_get_default_app_state.ts b/test/functional/apps/discover/context_awareness/extensions/_get_default_app_state.ts index 7e057da66b764..477c268a2f186 100644 --- a/test/functional/apps/discover/context_awareness/extensions/_get_default_app_state.ts +++ b/test/functional/apps/discover/context_awareness/extensions/_get_default_app_state.ts @@ -89,6 +89,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToActualUrl('discover', `?_a=${state}`, { ensureCurrentUrl: false, }); + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.discover.waitUntilSearchingHasFinished(); await PageObjects.unifiedFieldList.clickFieldListItemRemove('log.level'); await PageObjects.unifiedFieldList.clickFieldListItemRemove('message'); @@ -128,7 +129,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); - await dataViews.switchTo('my-example-logs'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataViews.switchToAndValidate('my-example-logs'); await expectColumns(['@timestamp', 'log.level', 'message']); await dataGrid.clickGridSettings(); const rowHeightValue = await dataGrid.getCurrentRowHeightValue(); @@ -141,14 +144,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); - await dataViews.switchTo('my-example-*'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataViews.switchToAndValidate('my-example-*'); await expectColumns(['@timestamp', 'Document']); await dataGrid.clickGridSettings(); let rowHeightValue = await dataGrid.getCurrentRowHeightValue(); expect(rowHeightValue).to.be('Custom'); let rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(3); - await dataViews.switchTo('my-example-logs'); + await dataViews.switchToAndValidate('my-example-logs'); await expectColumns(['@timestamp', 'log.level', 'message']); await dataGrid.clickGridSettings(); rowHeightValue = await dataGrid.getCurrentRowHeightValue(); @@ -161,7 +166,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); - await dataViews.switchTo('my-example-logs'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataViews.switchToAndValidate('my-example-logs'); await PageObjects.discover.waitUntilSearchingHasFinished(); await PageObjects.unifiedFieldList.clickFieldListItemRemove('log.level'); await PageObjects.unifiedFieldList.clickFieldListItemRemove('message'); @@ -186,7 +193,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); - await dataViews.switchTo('my-example-logs'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataViews.switchToAndValidate('my-example-logs'); await expectColumns(['@timestamp', 'log.level', 'message', 'data_stream.type']); }); }); diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_cell_renderers.ts b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_cell_renderers.ts index 4eaca072d3b1e..e25c833c80441 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_cell_renderers.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_cell_renderers.ts @@ -7,6 +7,7 @@ import kbnRison from '@kbn/rison'; import expect from '@kbn/expect'; +import type { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import type { FtrProviderContext } from '../../../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { @@ -23,6 +24,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const dataViews = getService('dataViews'); const queryBar = getService('queryBar'); const browser = getService('browser'); + const retry = getService('retry'); describe('extension getCellRenderers', () => { before(async () => { @@ -45,8 +47,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToActualUrl('discover', `?_a=${state}`, { ensureCurrentUrl: false, }); + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.discover.waitUntilSearchingHasFinished(); await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 0); const logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-'); expect(await logLevelBadge.getVisibleText()).to.be('debug'); @@ -65,11 +71,17 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToActualUrl('discover', `?_a=${state}`, { ensureCurrentUrl: false, }); + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.discover.waitUntilSearchingHasFinished(); await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); - const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 0); - expect(await firstCell.getVisibleText()).to.be('debug'); - await testSubjects.missingOrFail('*logLevelBadgeCell-'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + await retry.try(async () => { + const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 0); + expect(await firstCell.getVisibleText()).to.be('debug'); + await testSubjects.missingOrFail('*logLevelBadgeCell-'); + }); }); }); @@ -78,17 +90,28 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); - await dataViews.switchTo('my-example-logs,logstash*'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataViews.switchToAndValidate('my-example-logs,logstash*'); await queryBar.setQuery('log.level:*'); await queryBar.submitQuery(); + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.discover.waitUntilSearchingHasFinished(); await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); - let firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1); - let logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-'); - expect(await logLevelBadge.getVisibleText()).to.be('debug'); - expect(await logLevelBadge.getComputedStyle('background-color')).to.be( - 'rgba(190, 207, 227, 1)' - ); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + let firstCell: WebElementWrapper; + let logLevelBadge: WebElementWrapper; + + await retry.try(async () => { + firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1); + logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-'); + expect(await logLevelBadge.getVisibleText()).to.be('debug'); + expect(await logLevelBadge.getComputedStyle('background-color')).to.be( + 'rgba(190, 207, 227, 1)' + ); + }); // check Surrounding docs page await dataGrid.clickRowToggle(); @@ -98,26 +121,38 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await browser.refresh(); await PageObjects.header.waitUntilLoadingHasFinished(); - firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1); - logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-'); - expect(await logLevelBadge.getVisibleText()).to.be('debug'); - expect(await logLevelBadge.getComputedStyle('background-color')).to.be( - 'rgba(190, 207, 227, 1)' - ); + await retry.try(async () => { + firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1); + logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-'); + expect(await logLevelBadge.getVisibleText()).to.be('debug'); + expect(await logLevelBadge.getComputedStyle('background-color')).to.be( + 'rgba(190, 207, 227, 1)' + ); + }); }); it("should not render log.level badge cell if it's not a logs data source", async () => { await PageObjects.common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); - await dataViews.switchTo('my-example-*'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataViews.switchToAndValidate('my-example-*'); await queryBar.setQuery('log.level:*'); await queryBar.submitQuery(); + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.discover.waitUntilSearchingHasFinished(); await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); - let firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1); - expect(await firstCell.getVisibleText()).to.be('debug'); - await testSubjects.missingOrFail('*logLevelBadgeCell-'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + let firstCell: WebElementWrapper; + + await retry.try(async () => { + firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1); + expect(await firstCell.getVisibleText()).to.be('debug'); + await testSubjects.missingOrFail('*logLevelBadgeCell-'); + }); // check Surrounding docs page await dataGrid.clickRowToggle(); @@ -127,9 +162,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await browser.refresh(); await PageObjects.header.waitUntilLoadingHasFinished(); - firstCell = await dataGrid.getCellElementExcludingControlColumns(1, 1); - expect(await firstCell.getVisibleText()).to.be('debug'); - await testSubjects.missingOrFail('*logLevelBadgeCell-'); + await retry.try(async () => { + firstCell = await dataGrid.getCellElementExcludingControlColumns(1, 1); + expect(await firstCell.getVisibleText()).to.be('debug'); + await testSubjects.missingOrFail('*logLevelBadgeCell-'); + }); }); }); }); diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_default_app_state.ts b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_default_app_state.ts index 1755d386d4554..0aa58e85056ba 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_default_app_state.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_default_app_state.ts @@ -98,6 +98,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToActualUrl('discover', `?_a=${state}`, { ensureCurrentUrl: false, }); + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.discover.waitUntilSearchingHasFinished(); await PageObjects.unifiedFieldList.clickFieldListItemRemove('log.level'); await PageObjects.unifiedFieldList.clickFieldListItemRemove('message'); @@ -132,13 +133,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - // FLAKY: https://github.com/elastic/kibana/issues/191260 - describe.skip('data view mode', () => { + describe('data view mode', () => { it('should render default columns and row height', async () => { await PageObjects.common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); - await dataViews.switchTo('my-example-logs'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataViews.switchToAndValidate('my-example-logs'); await expectColumns(['@timestamp', 'log.level', 'message']); await dataGrid.clickGridSettings(); const rowHeightValue = await dataGrid.getCurrentRowHeightValue(); @@ -151,14 +153,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); - await dataViews.switchTo('my-example-*'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataViews.switchToAndValidate('my-example-*'); await expectColumns(['@timestamp', 'Document']); await dataGrid.clickGridSettings(); let rowHeightValue = await dataGrid.getCurrentRowHeightValue(); expect(rowHeightValue).to.be('Custom'); let rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(3); - await dataViews.switchTo('my-example-logs'); + await dataViews.switchToAndValidate('my-example-logs'); await expectColumns(['@timestamp', 'log.level', 'message']); await dataGrid.clickGridSettings(); rowHeightValue = await dataGrid.getCurrentRowHeightValue(); @@ -171,7 +175,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); - await dataViews.switchTo('my-example-logs'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataViews.switchToAndValidate('my-example-logs'); + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.discover.waitUntilSearchingHasFinished(); await PageObjects.unifiedFieldList.clickFieldListItemRemove('log.level'); await PageObjects.unifiedFieldList.clickFieldListItemRemove('message'); @@ -196,7 +203,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); - await dataViews.switchTo('my-example-logs'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataViews.switchToAndValidate('my-example-logs'); await expectColumns(['@timestamp', 'log.level', 'message', 'data_stream.type']); }); }); From c3450949eeb9c1a07ac43313e6a648cec7a20884 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:59:53 +1000 Subject: [PATCH 12/99] [api-docs] 2024-09-05 Daily api_docs build (#192146) Generated by https://buildkite.com/elastic/kibana-api-docs-daily/builds/821 --- api_docs/actions.mdx | 2 +- api_docs/advanced_settings.mdx | 2 +- .../ai_assistant_management_selection.mdx | 2 +- api_docs/aiops.mdx | 2 +- api_docs/alerting.mdx | 2 +- api_docs/apm.mdx | 2 +- api_docs/apm_data_access.mdx | 2 +- api_docs/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.devdocs.json | 128 +++- api_docs/controls.mdx | 4 +- api_docs/custom_integrations.mdx | 2 +- api_docs/dashboard.devdocs.json | 18 +- api_docs/dashboard.mdx | 2 +- api_docs/dashboard_enhanced.mdx | 2 +- api_docs/data.mdx | 2 +- api_docs/data_quality.mdx | 2 +- api_docs/data_query.mdx | 2 +- api_docs/data_search.mdx | 2 +- api_docs/data_view_editor.mdx | 2 +- api_docs/data_view_field_editor.mdx | 2 +- api_docs/data_view_management.mdx | 2 +- api_docs/data_views.mdx | 2 +- api_docs/data_visualizer.mdx | 2 +- api_docs/dataset_quality.mdx | 2 +- api_docs/deprecations_by_api.mdx | 2 +- api_docs/deprecations_by_plugin.mdx | 4 +- api_docs/deprecations_by_team.mdx | 2 +- api_docs/dev_tools.mdx | 2 +- api_docs/discover.mdx | 2 +- api_docs/discover_enhanced.mdx | 2 +- api_docs/discover_shared.mdx | 2 +- api_docs/ecs_data_quality_dashboard.mdx | 2 +- api_docs/elastic_assistant.mdx | 2 +- api_docs/embeddable.devdocs.json | 115 ++-- api_docs/embeddable.mdx | 2 +- api_docs/embeddable_enhanced.mdx | 2 +- api_docs/encrypted_saved_objects.mdx | 2 +- api_docs/enterprise_search.mdx | 2 +- api_docs/entities_data_access.mdx | 2 +- api_docs/entity_manager.mdx | 2 +- api_docs/es_ui_shared.mdx | 2 +- api_docs/esql.mdx | 2 +- api_docs/esql_data_grid.mdx | 2 +- api_docs/event_annotation.mdx | 2 +- api_docs/event_annotation_listing.mdx | 2 +- api_docs/event_log.mdx | 2 +- api_docs/exploratory_view.mdx | 2 +- api_docs/expression_error.mdx | 2 +- api_docs/expression_gauge.mdx | 2 +- api_docs/expression_heatmap.mdx | 2 +- api_docs/expression_image.mdx | 2 +- api_docs/expression_legacy_metric_vis.mdx | 2 +- api_docs/expression_metric.mdx | 2 +- api_docs/expression_metric_vis.mdx | 2 +- api_docs/expression_partition_vis.mdx | 2 +- api_docs/expression_repeat_image.mdx | 2 +- api_docs/expression_reveal_image.mdx | 2 +- api_docs/expression_shape.mdx | 2 +- api_docs/expression_tagcloud.mdx | 2 +- api_docs/expression_x_y.mdx | 2 +- api_docs/expressions.mdx | 2 +- api_docs/features.mdx | 2 +- api_docs/field_formats.mdx | 2 +- api_docs/fields_metadata.mdx | 2 +- api_docs/file_upload.mdx | 2 +- api_docs/files.mdx | 2 +- api_docs/files_management.mdx | 2 +- api_docs/fleet.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/inference.devdocs.json | 562 +++++++++++++++++- api_docs/inference.mdx | 15 +- api_docs/infra.mdx | 2 +- api_docs/ingest_pipelines.mdx | 2 +- api_docs/inspector.mdx | 2 +- api_docs/integration_assistant.mdx | 2 +- api_docs/interactive_setup.mdx | 2 +- api_docs/investigate.mdx | 2 +- api_docs/investigate_app.mdx | 2 +- api_docs/kbn_ace.mdx | 2 +- api_docs/kbn_actions_types.mdx | 2 +- api_docs/kbn_aiops_components.mdx | 2 +- api_docs/kbn_aiops_log_pattern_analysis.mdx | 2 +- api_docs/kbn_aiops_log_rate_analysis.mdx | 2 +- .../kbn_alerting_api_integration_helpers.mdx | 2 +- api_docs/kbn_alerting_comparators.mdx | 2 +- api_docs/kbn_alerting_state_types.mdx | 2 +- api_docs/kbn_alerting_types.mdx | 2 +- api_docs/kbn_alerts_as_data_utils.mdx | 2 +- api_docs/kbn_alerts_grouping.mdx | 2 +- api_docs/kbn_alerts_ui_shared.mdx | 2 +- api_docs/kbn_analytics.mdx | 2 +- api_docs/kbn_analytics_collection_utils.mdx | 2 +- api_docs/kbn_apm_config_loader.mdx | 2 +- api_docs/kbn_apm_data_view.mdx | 2 +- api_docs/kbn_apm_synthtrace.devdocs.json | 71 +++ api_docs/kbn_apm_synthtrace.mdx | 4 +- .../kbn_apm_synthtrace_client.devdocs.json | 45 ++ api_docs/kbn_apm_synthtrace_client.mdx | 4 +- api_docs/kbn_apm_types.mdx | 2 +- api_docs/kbn_apm_utils.mdx | 2 +- api_docs/kbn_avc_banner.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_cbor.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_cloud_security_posture.mdx | 2 +- ...cloud_security_posture_common.devdocs.json | 48 ++ .../kbn_cloud_security_posture_common.mdx | 4 +- api_docs/kbn_code_editor.mdx | 2 +- api_docs/kbn_code_editor_mock.mdx | 2 +- api_docs/kbn_code_owners.mdx | 2 +- api_docs/kbn_coloring.mdx | 2 +- api_docs/kbn_config.mdx | 2 +- api_docs/kbn_config_mocks.mdx | 2 +- api_docs/kbn_config_schema.mdx | 2 +- .../kbn_content_management_content_editor.mdx | 2 +- ...ent_management_content_insights_public.mdx | 2 +- ...ent_management_content_insights_server.mdx | 2 +- ...bn_content_management_favorites_public.mdx | 2 +- ...bn_content_management_favorites_server.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 +- .../kbn_content_management_user_profiles.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 +- ...kbn_core_elasticsearch_server.devdocs.json | 16 + api_docs/kbn_core_elasticsearch_server.mdx | 4 +- ...elasticsearch_server_internal.devdocs.json | 12 +- ...kbn_core_elasticsearch_server_internal.mdx | 2 +- ...re_elasticsearch_server_mocks.devdocs.json | 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.devdocs.json | 4 + api_docs/kbn_core_http_server.mdx | 2 +- api_docs/kbn_core_http_server_internal.mdx | 2 +- api_docs/kbn_core_http_server_mocks.mdx | 2 +- api_docs/kbn_core_i18n_browser.mdx | 2 +- api_docs/kbn_core_i18n_browser_mocks.mdx | 2 +- api_docs/kbn_core_i18n_server.mdx | 2 +- api_docs/kbn_core_i18n_server_internal.mdx | 2 +- api_docs/kbn_core_i18n_server_mocks.mdx | 2 +- ...n_core_injected_metadata_browser_mocks.mdx | 2 +- ...kbn_core_integrations_browser_internal.mdx | 2 +- .../kbn_core_integrations_browser_mocks.mdx | 2 +- api_docs/kbn_core_lifecycle_browser.mdx | 2 +- api_docs/kbn_core_lifecycle_browser_mocks.mdx | 2 +- api_docs/kbn_core_lifecycle_server.mdx | 2 +- api_docs/kbn_core_lifecycle_server_mocks.mdx | 2 +- api_docs/kbn_core_logging_browser_mocks.mdx | 2 +- api_docs/kbn_core_logging_common_internal.mdx | 2 +- api_docs/kbn_core_logging_server.mdx | 2 +- api_docs/kbn_core_logging_server_internal.mdx | 2 +- api_docs/kbn_core_logging_server_mocks.mdx | 2 +- ...ore_metrics_collectors_server_internal.mdx | 2 +- ...n_core_metrics_collectors_server_mocks.mdx | 2 +- api_docs/kbn_core_metrics_server.mdx | 2 +- api_docs/kbn_core_metrics_server_internal.mdx | 2 +- api_docs/kbn_core_metrics_server_mocks.mdx | 2 +- api_docs/kbn_core_mount_utils_browser.mdx | 2 +- api_docs/kbn_core_node_server.mdx | 2 +- api_docs/kbn_core_node_server_internal.mdx | 2 +- api_docs/kbn_core_node_server_mocks.mdx | 2 +- api_docs/kbn_core_notifications_browser.mdx | 2 +- ...bn_core_notifications_browser_internal.mdx | 2 +- .../kbn_core_notifications_browser_mocks.mdx | 2 +- api_docs/kbn_core_overlays_browser.mdx | 2 +- .../kbn_core_overlays_browser_internal.mdx | 2 +- api_docs/kbn_core_overlays_browser_mocks.mdx | 2 +- api_docs/kbn_core_plugins_browser.mdx | 2 +- api_docs/kbn_core_plugins_browser_mocks.mdx | 2 +- .../kbn_core_plugins_contracts_browser.mdx | 2 +- .../kbn_core_plugins_contracts_server.mdx | 2 +- api_docs/kbn_core_plugins_server.mdx | 2 +- api_docs/kbn_core_plugins_server_mocks.mdx | 2 +- api_docs/kbn_core_preboot_server.mdx | 2 +- api_docs/kbn_core_preboot_server_mocks.mdx | 2 +- api_docs/kbn_core_rendering_browser_mocks.mdx | 2 +- .../kbn_core_rendering_server_internal.mdx | 2 +- api_docs/kbn_core_rendering_server_mocks.mdx | 2 +- api_docs/kbn_core_root_server_internal.mdx | 2 +- .../kbn_core_saved_objects_api_browser.mdx | 2 +- .../kbn_core_saved_objects_api_server.mdx | 2 +- ...bn_core_saved_objects_api_server_mocks.mdx | 2 +- ...ore_saved_objects_base_server_internal.mdx | 2 +- ...n_core_saved_objects_base_server_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_browser.mdx | 2 +- ...bn_core_saved_objects_browser_internal.mdx | 2 +- .../kbn_core_saved_objects_browser_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_common.mdx | 2 +- ..._objects_import_export_server_internal.mdx | 2 +- ...ved_objects_import_export_server_mocks.mdx | 2 +- ...aved_objects_migration_server_internal.mdx | 2 +- ...e_saved_objects_migration_server_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_server.mdx | 2 +- ...kbn_core_saved_objects_server_internal.mdx | 2 +- .../kbn_core_saved_objects_server_mocks.mdx | 2 +- .../kbn_core_saved_objects_utils_server.mdx | 2 +- api_docs/kbn_core_security_browser.mdx | 2 +- .../kbn_core_security_browser_internal.mdx | 2 +- api_docs/kbn_core_security_browser_mocks.mdx | 2 +- api_docs/kbn_core_security_common.mdx | 2 +- api_docs/kbn_core_security_server.mdx | 2 +- .../kbn_core_security_server_internal.mdx | 2 +- api_docs/kbn_core_security_server_mocks.mdx | 2 +- api_docs/kbn_core_status_common.mdx | 2 +- api_docs/kbn_core_status_common_internal.mdx | 2 +- api_docs/kbn_core_status_server.mdx | 2 +- api_docs/kbn_core_status_server_internal.mdx | 2 +- api_docs/kbn_core_status_server_mocks.mdx | 2 +- ...core_test_helpers_deprecations_getters.mdx | 2 +- ...n_core_test_helpers_http_setup_browser.mdx | 2 +- api_docs/kbn_core_test_helpers_kbn_server.mdx | 2 +- .../kbn_core_test_helpers_model_versions.mdx | 2 +- ...n_core_test_helpers_so_type_serializer.mdx | 2 +- api_docs/kbn_core_test_helpers_test_utils.mdx | 2 +- api_docs/kbn_core_theme_browser.mdx | 2 +- api_docs/kbn_core_theme_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_browser.mdx | 2 +- .../kbn_core_ui_settings_browser_internal.mdx | 2 +- .../kbn_core_ui_settings_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_common.mdx | 2 +- api_docs/kbn_core_ui_settings_server.mdx | 2 +- .../kbn_core_ui_settings_server_internal.mdx | 2 +- .../kbn_core_ui_settings_server_mocks.mdx | 2 +- api_docs/kbn_core_usage_data_server.mdx | 2 +- .../kbn_core_usage_data_server_internal.mdx | 2 +- api_docs/kbn_core_usage_data_server_mocks.mdx | 2 +- api_docs/kbn_core_user_profile_browser.mdx | 2 +- ...kbn_core_user_profile_browser_internal.mdx | 2 +- .../kbn_core_user_profile_browser_mocks.mdx | 2 +- api_docs/kbn_core_user_profile_common.mdx | 2 +- api_docs/kbn_core_user_profile_server.mdx | 2 +- .../kbn_core_user_profile_server_internal.mdx | 2 +- .../kbn_core_user_profile_server_mocks.mdx | 2 +- api_docs/kbn_core_user_settings_server.mdx | 2 +- .../kbn_core_user_settings_server_mocks.mdx | 2 +- api_docs/kbn_crypto.mdx | 2 +- api_docs/kbn_crypto_browser.mdx | 2 +- api_docs/kbn_custom_icons.mdx | 2 +- api_docs/kbn_custom_integrations.mdx | 2 +- api_docs/kbn_cypress_config.mdx | 2 +- api_docs/kbn_data_forge.mdx | 2 +- api_docs/kbn_data_service.mdx | 2 +- api_docs/kbn_data_stream_adapter.mdx | 2 +- api_docs/kbn_data_view_utils.mdx | 2 +- api_docs/kbn_datemath.mdx | 2 +- api_docs/kbn_deeplinks_analytics.mdx | 2 +- api_docs/kbn_deeplinks_devtools.mdx | 2 +- api_docs/kbn_deeplinks_fleet.mdx | 2 +- api_docs/kbn_deeplinks_management.mdx | 2 +- api_docs/kbn_deeplinks_ml.mdx | 2 +- api_docs/kbn_deeplinks_observability.mdx | 2 +- api_docs/kbn_deeplinks_search.mdx | 2 +- api_docs/kbn_deeplinks_security.mdx | 2 +- api_docs/kbn_deeplinks_shared.mdx | 2 +- api_docs/kbn_default_nav_analytics.mdx | 2 +- api_docs/kbn_default_nav_devtools.mdx | 2 +- api_docs/kbn_default_nav_management.mdx | 2 +- api_docs/kbn_default_nav_ml.mdx | 2 +- api_docs/kbn_dev_cli_errors.mdx | 2 +- api_docs/kbn_dev_cli_runner.mdx | 2 +- api_docs/kbn_dev_proc_runner.mdx | 2 +- api_docs/kbn_dev_utils.mdx | 2 +- api_docs/kbn_discover_utils.mdx | 2 +- api_docs/kbn_doc_links.mdx | 2 +- api_docs/kbn_docs_utils.mdx | 2 +- api_docs/kbn_dom_drag_drop.mdx | 2 +- api_docs/kbn_ebt_tools.mdx | 2 +- api_docs/kbn_ecs_data_quality_dashboard.mdx | 2 +- api_docs/kbn_elastic_agent_utils.mdx | 2 +- api_docs/kbn_elastic_assistant.mdx | 2 +- api_docs/kbn_elastic_assistant_common.mdx | 2 +- api_docs/kbn_entities_schema.mdx | 2 +- api_docs/kbn_es.mdx | 2 +- api_docs/kbn_es_archiver.mdx | 2 +- api_docs/kbn_es_errors.mdx | 2 +- api_docs/kbn_es_query.mdx | 2 +- api_docs/kbn_es_types.mdx | 2 +- api_docs/kbn_eslint_plugin_imports.mdx | 2 +- api_docs/kbn_esql_ast.mdx | 2 +- api_docs/kbn_esql_utils.mdx | 2 +- ..._esql_validation_autocomplete.devdocs.json | 16 + api_docs/kbn_esql_validation_autocomplete.mdx | 4 +- api_docs/kbn_event_annotation_common.mdx | 2 +- api_docs/kbn_event_annotation_components.mdx | 2 +- api_docs/kbn_expandable_flyout.mdx | 2 +- api_docs/kbn_field_types.mdx | 2 +- api_docs/kbn_field_utils.mdx | 2 +- api_docs/kbn_find_used_node_modules.mdx | 2 +- api_docs/kbn_formatters.mdx | 2 +- .../kbn_ftr_common_functional_services.mdx | 2 +- .../kbn_ftr_common_functional_ui_services.mdx | 2 +- api_docs/kbn_generate.mdx | 2 +- api_docs/kbn_generate_console_definitions.mdx | 2 +- api_docs/kbn_generate_csv.mdx | 2 +- api_docs/kbn_grid_layout.mdx | 2 +- api_docs/kbn_grouping.mdx | 2 +- api_docs/kbn_guided_onboarding.mdx | 2 +- api_docs/kbn_handlebars.mdx | 2 +- api_docs/kbn_hapi_mocks.mdx | 2 +- api_docs/kbn_health_gateway_server.mdx | 2 +- api_docs/kbn_home_sample_data_card.mdx | 2 +- api_docs/kbn_home_sample_data_tab.mdx | 2 +- api_docs/kbn_i18n.mdx | 2 +- api_docs/kbn_i18n_react.mdx | 2 +- api_docs/kbn_import_resolver.mdx | 2 +- api_docs/kbn_index_management.mdx | 2 +- api_docs/kbn_inference_integration_flyout.mdx | 2 +- api_docs/kbn_infra_forge.mdx | 2 +- api_docs/kbn_interpreter.mdx | 2 +- api_docs/kbn_investigation_shared.mdx | 2 +- api_docs/kbn_io_ts_utils.mdx | 2 +- api_docs/kbn_ipynb.mdx | 2 +- api_docs/kbn_jest_serializers.mdx | 2 +- api_docs/kbn_journeys.mdx | 2 +- api_docs/kbn_json_ast.mdx | 2 +- api_docs/kbn_json_schemas.mdx | 2 +- api_docs/kbn_kibana_manifest_schema.mdx | 2 +- .../kbn_language_documentation_popover.mdx | 2 +- api_docs/kbn_lens_embeddable_utils.mdx | 2 +- api_docs/kbn_lens_formula_docs.mdx | 2 +- api_docs/kbn_logging.mdx | 2 +- api_docs/kbn_logging_mocks.mdx | 2 +- api_docs/kbn_managed_content_badge.mdx | 2 +- api_docs/kbn_managed_vscode_config.mdx | 2 +- api_docs/kbn_management_cards_navigation.mdx | 2 +- .../kbn_management_settings_application.mdx | 2 +- ...ent_settings_components_field_category.mdx | 2 +- ...gement_settings_components_field_input.mdx | 2 +- ...nagement_settings_components_field_row.mdx | 2 +- ...bn_management_settings_components_form.mdx | 2 +- ...n_management_settings_field_definition.mdx | 2 +- api_docs/kbn_management_settings_ids.mdx | 2 +- ...n_management_settings_section_registry.mdx | 2 +- api_docs/kbn_management_settings_types.mdx | 2 +- .../kbn_management_settings_utilities.mdx | 2 +- api_docs/kbn_management_storybook_config.mdx | 2 +- api_docs/kbn_mapbox_gl.mdx | 2 +- api_docs/kbn_maps_vector_tile_utils.mdx | 2 +- api_docs/kbn_ml_agg_utils.mdx | 2 +- api_docs/kbn_ml_anomaly_utils.mdx | 2 +- api_docs/kbn_ml_cancellable_search.mdx | 2 +- api_docs/kbn_ml_category_validator.mdx | 2 +- api_docs/kbn_ml_chi2test.mdx | 2 +- .../kbn_ml_data_frame_analytics_utils.mdx | 2 +- api_docs/kbn_ml_data_grid.mdx | 2 +- api_docs/kbn_ml_date_picker.mdx | 2 +- api_docs/kbn_ml_date_utils.mdx | 2 +- api_docs/kbn_ml_error_utils.mdx | 2 +- api_docs/kbn_ml_in_memory_table.mdx | 2 +- api_docs/kbn_ml_is_defined.mdx | 2 +- api_docs/kbn_ml_is_populated_object.mdx | 2 +- api_docs/kbn_ml_kibana_theme.mdx | 2 +- api_docs/kbn_ml_local_storage.mdx | 2 +- api_docs/kbn_ml_nested_property.mdx | 2 +- api_docs/kbn_ml_number_utils.mdx | 2 +- api_docs/kbn_ml_query_utils.mdx | 2 +- api_docs/kbn_ml_random_sampler_utils.mdx | 2 +- api_docs/kbn_ml_route_utils.mdx | 2 +- api_docs/kbn_ml_runtime_field_utils.mdx | 2 +- api_docs/kbn_ml_string_hash.mdx | 2 +- api_docs/kbn_ml_time_buckets.mdx | 2 +- api_docs/kbn_ml_trained_models_utils.mdx | 2 +- api_docs/kbn_ml_ui_actions.mdx | 2 +- api_docs/kbn_ml_url_state.mdx | 2 +- api_docs/kbn_mock_idp_utils.mdx | 2 +- api_docs/kbn_monaco.devdocs.json | 16 + api_docs/kbn_monaco.mdx | 4 +- api_docs/kbn_object_versioning.mdx | 2 +- api_docs/kbn_object_versioning_utils.mdx | 2 +- api_docs/kbn_observability_alert_details.mdx | 2 +- .../kbn_observability_alerting_rule_utils.mdx | 2 +- .../kbn_observability_alerting_test_data.mdx | 2 +- ...ility_get_padded_alert_time_range_util.mdx | 2 +- api_docs/kbn_openapi_bundler.mdx | 2 +- api_docs/kbn_openapi_generator.mdx | 2 +- api_docs/kbn_optimizer.mdx | 2 +- api_docs/kbn_optimizer_webpack_helpers.mdx | 2 +- api_docs/kbn_osquery_io_ts_types.mdx | 2 +- api_docs/kbn_panel_loader.mdx | 2 +- ..._performance_testing_dataset_extractor.mdx | 2 +- api_docs/kbn_plugin_check.mdx | 2 +- api_docs/kbn_plugin_generator.mdx | 2 +- api_docs/kbn_plugin_helpers.mdx | 2 +- api_docs/kbn_presentation_containers.mdx | 2 +- api_docs/kbn_presentation_publishing.mdx | 2 +- api_docs/kbn_profiling_utils.mdx | 2 +- api_docs/kbn_random_sampling.mdx | 2 +- api_docs/kbn_react_field.mdx | 2 +- api_docs/kbn_react_hooks.mdx | 2 +- api_docs/kbn_react_kibana_context_common.mdx | 2 +- api_docs/kbn_react_kibana_context_render.mdx | 2 +- api_docs/kbn_react_kibana_context_root.mdx | 2 +- api_docs/kbn_react_kibana_context_styled.mdx | 2 +- api_docs/kbn_react_kibana_context_theme.mdx | 2 +- api_docs/kbn_react_kibana_mount.mdx | 2 +- api_docs/kbn_recently_accessed.mdx | 2 +- api_docs/kbn_repo_file_maps.mdx | 2 +- api_docs/kbn_repo_linter.mdx | 2 +- api_docs/kbn_repo_path.mdx | 2 +- api_docs/kbn_repo_source_classifier.mdx | 2 +- api_docs/kbn_reporting_common.mdx | 2 +- api_docs/kbn_reporting_csv_share_panel.mdx | 2 +- api_docs/kbn_reporting_export_types_csv.mdx | 2 +- .../kbn_reporting_export_types_csv_common.mdx | 2 +- api_docs/kbn_reporting_export_types_pdf.mdx | 2 +- .../kbn_reporting_export_types_pdf_common.mdx | 2 +- api_docs/kbn_reporting_export_types_png.mdx | 2 +- .../kbn_reporting_export_types_png_common.mdx | 2 +- api_docs/kbn_reporting_mocks_server.mdx | 2 +- api_docs/kbn_reporting_public.mdx | 2 +- api_docs/kbn_reporting_server.mdx | 2 +- api_docs/kbn_resizable_layout.mdx | 2 +- .../kbn_response_ops_feature_flag_service.mdx | 2 +- api_docs/kbn_rison.mdx | 2 +- api_docs/kbn_rollup.mdx | 2 +- api_docs/kbn_router_to_openapispec.mdx | 2 +- api_docs/kbn_router_utils.mdx | 2 +- api_docs/kbn_rrule.mdx | 2 +- api_docs/kbn_rule_data_utils.mdx | 2 +- api_docs/kbn_saved_objects_settings.mdx | 2 +- api_docs/kbn_screenshotting_server.mdx | 2 +- api_docs/kbn_search_api_panels.mdx | 2 +- api_docs/kbn_search_connectors.mdx | 2 +- api_docs/kbn_search_errors.mdx | 2 +- api_docs/kbn_search_index_documents.mdx | 2 +- api_docs/kbn_search_response_warnings.mdx | 2 +- api_docs/kbn_search_types.mdx | 2 +- api_docs/kbn_security_api_key_management.mdx | 2 +- api_docs/kbn_security_authorization_core.mdx | 2 +- api_docs/kbn_security_form_components.mdx | 2 +- api_docs/kbn_security_hardening.mdx | 2 +- api_docs/kbn_security_plugin_types_common.mdx | 2 +- api_docs/kbn_security_plugin_types_public.mdx | 2 +- api_docs/kbn_security_plugin_types_server.mdx | 2 +- .../kbn_security_role_management_model.mdx | 2 +- api_docs/kbn_security_solution_common.mdx | 2 +- ...kbn_security_solution_distribution_bar.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 +- api_docs/kbn_security_ui_components.mdx | 2 +- .../kbn_securitysolution_autocomplete.mdx | 2 +- api_docs/kbn_securitysolution_data_table.mdx | 2 +- api_docs/kbn_securitysolution_ecs.mdx | 2 +- api_docs/kbn_securitysolution_es_utils.mdx | 2 +- ...ritysolution_exception_list_components.mdx | 2 +- api_docs/kbn_securitysolution_hook_utils.mdx | 2 +- ..._securitysolution_io_ts_alerting_types.mdx | 2 +- .../kbn_securitysolution_io_ts_list_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_utils.mdx | 2 +- api_docs/kbn_securitysolution_list_api.mdx | 2 +- .../kbn_securitysolution_list_constants.mdx | 2 +- api_docs/kbn_securitysolution_list_hooks.mdx | 2 +- api_docs/kbn_securitysolution_list_utils.mdx | 2 +- api_docs/kbn_securitysolution_rules.mdx | 2 +- api_docs/kbn_securitysolution_t_grid.mdx | 2 +- api_docs/kbn_securitysolution_utils.mdx | 2 +- api_docs/kbn_server_http_tools.mdx | 2 +- api_docs/kbn_server_route_repository.mdx | 2 +- .../kbn_server_route_repository_client.mdx | 2 +- .../kbn_server_route_repository_utils.mdx | 2 +- api_docs/kbn_serverless_common_settings.mdx | 2 +- .../kbn_serverless_observability_settings.mdx | 2 +- api_docs/kbn_serverless_project_switcher.mdx | 2 +- api_docs/kbn_serverless_search_settings.mdx | 2 +- api_docs/kbn_serverless_security_settings.mdx | 2 +- api_docs/kbn_serverless_storybook_config.mdx | 2 +- api_docs/kbn_shared_svg.mdx | 2 +- api_docs/kbn_shared_ux_avatar_solution.mdx | 2 +- .../kbn_shared_ux_button_exit_full_screen.mdx | 2 +- api_docs/kbn_shared_ux_button_toolbar.mdx | 2 +- api_docs/kbn_shared_ux_card_no_data.mdx | 2 +- api_docs/kbn_shared_ux_card_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_chrome_navigation.mdx | 2 +- api_docs/kbn_shared_ux_error_boundary.mdx | 2 +- api_docs/kbn_shared_ux_file_context.mdx | 2 +- api_docs/kbn_shared_ux_file_image.mdx | 2 +- api_docs/kbn_shared_ux_file_image_mocks.mdx | 2 +- api_docs/kbn_shared_ux_file_mocks.mdx | 2 +- api_docs/kbn_shared_ux_file_picker.mdx | 2 +- api_docs/kbn_shared_ux_file_types.mdx | 2 +- api_docs/kbn_shared_ux_file_upload.mdx | 2 +- api_docs/kbn_shared_ux_file_util.mdx | 2 +- api_docs/kbn_shared_ux_link_redirect_app.mdx | 2 +- .../kbn_shared_ux_link_redirect_app_mocks.mdx | 2 +- api_docs/kbn_shared_ux_markdown.mdx | 2 +- api_docs/kbn_shared_ux_markdown_mocks.mdx | 2 +- .../kbn_shared_ux_page_analytics_no_data.mdx | 2 +- ...shared_ux_page_analytics_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_page_kibana_no_data.mdx | 2 +- ...bn_shared_ux_page_kibana_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_page_kibana_template.mdx | 2 +- ...n_shared_ux_page_kibana_template_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_no_data.mdx | 2 +- .../kbn_shared_ux_page_no_data_config.mdx | 2 +- ...bn_shared_ux_page_no_data_config_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_solution_nav.mdx | 2 +- .../kbn_shared_ux_prompt_no_data_views.mdx | 2 +- ...n_shared_ux_prompt_no_data_views_mocks.mdx | 2 +- api_docs/kbn_shared_ux_prompt_not_found.mdx | 2 +- api_docs/kbn_shared_ux_router.mdx | 2 +- api_docs/kbn_shared_ux_router_mocks.mdx | 2 +- api_docs/kbn_shared_ux_storybook_config.mdx | 2 +- api_docs/kbn_shared_ux_storybook_mock.mdx | 2 +- api_docs/kbn_shared_ux_tabbed_modal.mdx | 2 +- api_docs/kbn_shared_ux_table_persist.mdx | 2 +- api_docs/kbn_shared_ux_utility.mdx | 2 +- api_docs/kbn_slo_schema.mdx | 2 +- api_docs/kbn_some_dev_log.mdx | 2 +- api_docs/kbn_sort_predicates.mdx | 2 +- api_docs/kbn_std.mdx | 2 +- api_docs/kbn_stdio_dev_helpers.mdx | 2 +- api_docs/kbn_storybook.mdx | 2 +- api_docs/kbn_synthetics_e2e.mdx | 2 +- api_docs/kbn_synthetics_private_location.mdx | 2 +- api_docs/kbn_telemetry_tools.mdx | 2 +- api_docs/kbn_test.mdx | 2 +- api_docs/kbn_test_eui_helpers.mdx | 2 +- api_docs/kbn_test_jest_helpers.mdx | 2 +- api_docs/kbn_test_subj_selector.mdx | 2 +- api_docs/kbn_text_based_editor.mdx | 2 +- api_docs/kbn_timerange.mdx | 2 +- api_docs/kbn_tooling_log.mdx | 2 +- api_docs/kbn_triggers_actions_ui_types.mdx | 2 +- api_docs/kbn_try_in_console.mdx | 2 +- api_docs/kbn_ts_projects.mdx | 2 +- api_docs/kbn_typed_react_router_config.mdx | 2 +- api_docs/kbn_ui_actions_browser.mdx | 2 +- api_docs/kbn_ui_shared_deps_src.mdx | 2 +- api_docs/kbn_ui_theme.mdx | 2 +- api_docs/kbn_unified_data_table.mdx | 2 +- api_docs/kbn_unified_doc_viewer.mdx | 2 +- api_docs/kbn_unified_field_list.mdx | 2 +- api_docs/kbn_unsaved_changes_badge.mdx | 2 +- api_docs/kbn_unsaved_changes_prompt.mdx | 2 +- api_docs/kbn_use_tracked_promise.mdx | 2 +- api_docs/kbn_user_profile_components.mdx | 2 +- api_docs/kbn_utility_types.mdx | 2 +- api_docs/kbn_utility_types_jest.mdx | 2 +- api_docs/kbn_utils.mdx | 2 +- api_docs/kbn_visualization_ui_components.mdx | 2 +- api_docs/kbn_visualization_utils.mdx | 2 +- api_docs/kbn_xstate_utils.mdx | 2 +- api_docs/kbn_yarn_lock_validator.mdx | 2 +- api_docs/kbn_zod.mdx | 2 +- api_docs/kbn_zod_helpers.mdx | 2 +- api_docs/kibana_overview.mdx | 2 +- api_docs/kibana_react.mdx | 2 +- api_docs/kibana_utils.mdx | 2 +- api_docs/kubernetes_security.mdx | 2 +- api_docs/lens.mdx | 2 +- api_docs/license_api_guard.mdx | 2 +- api_docs/license_management.mdx | 2 +- api_docs/licensing.mdx | 2 +- api_docs/links.mdx | 2 +- api_docs/lists.mdx | 2 +- api_docs/logs_data_access.mdx | 2 +- api_docs/logs_explorer.mdx | 2 +- api_docs/logs_shared.mdx | 2 +- api_docs/management.mdx | 2 +- api_docs/maps.mdx | 2 +- api_docs/maps_ems.mdx | 2 +- api_docs/metrics_data_access.mdx | 2 +- api_docs/ml.mdx | 2 +- api_docs/mock_idp_plugin.mdx | 2 +- api_docs/monitoring.mdx | 2 +- api_docs/monitoring_collection.mdx | 2 +- api_docs/navigation.mdx | 2 +- api_docs/newsfeed.mdx | 2 +- api_docs/no_data_page.mdx | 2 +- api_docs/notifications.mdx | 2 +- api_docs/observability.mdx | 2 +- api_docs/observability_a_i_assistant.mdx | 2 +- api_docs/observability_a_i_assistant_app.mdx | 2 +- .../observability_ai_assistant_management.mdx | 2 +- api_docs/observability_logs_explorer.mdx | 2 +- api_docs/observability_onboarding.mdx | 2 +- api_docs/observability_shared.mdx | 2 +- api_docs/osquery.mdx | 2 +- api_docs/painless_lab.mdx | 2 +- api_docs/plugin_directory.mdx | 20 +- api_docs/presentation_panel.mdx | 2 +- api_docs/presentation_util.mdx | 2 +- api_docs/profiling.mdx | 2 +- api_docs/profiling_data_access.mdx | 2 +- api_docs/remote_clusters.mdx | 2 +- api_docs/reporting.mdx | 2 +- api_docs/rollup.mdx | 2 +- api_docs/rule_registry.mdx | 2 +- api_docs/runtime_fields.mdx | 2 +- api_docs/saved_objects.mdx | 2 +- api_docs/saved_objects_finder.mdx | 2 +- api_docs/saved_objects_management.mdx | 2 +- api_docs/saved_objects_tagging.mdx | 2 +- api_docs/saved_objects_tagging_oss.mdx | 2 +- api_docs/saved_search.mdx | 2 +- api_docs/screenshot_mode.mdx | 2 +- api_docs/screenshotting.mdx | 2 +- api_docs/search_assistant.mdx | 2 +- api_docs/search_connectors.mdx | 2 +- api_docs/search_homepage.mdx | 2 +- api_docs/search_indices.mdx | 2 +- api_docs/search_inference_endpoints.mdx | 2 +- api_docs/search_notebooks.mdx | 2 +- api_docs/search_playground.mdx | 2 +- api_docs/security.mdx | 2 +- api_docs/security_solution.mdx | 2 +- api_docs/security_solution_ess.mdx | 2 +- api_docs/security_solution_serverless.mdx | 2 +- api_docs/serverless.mdx | 2 +- api_docs/serverless_observability.mdx | 2 +- api_docs/serverless_search.mdx | 2 +- api_docs/session_view.mdx | 2 +- api_docs/share.mdx | 2 +- api_docs/slo.mdx | 2 +- api_docs/snapshot_restore.mdx | 2 +- api_docs/spaces.mdx | 2 +- api_docs/stack_alerts.mdx | 2 +- api_docs/stack_connectors.mdx | 2 +- api_docs/task_manager.mdx | 2 +- api_docs/telemetry.mdx | 2 +- api_docs/telemetry_collection_manager.mdx | 2 +- api_docs/telemetry_collection_xpack.mdx | 2 +- api_docs/telemetry_management_section.mdx | 2 +- api_docs/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 +- 744 files changed, 1736 insertions(+), 826 deletions(-) diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index a9d96a42f8957..a5de0b1fbab95 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-09-04 +date: 2024-09-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 e7b6e04447548..8c0ab2a644eb2 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/ai_assistant_management_selection.mdx b/api_docs/ai_assistant_management_selection.mdx index a348b7d5a8e41..a0eb3964e1552 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-09-04 +date: 2024-09-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 58226bd0cf12c..2fa494fa1a3ca 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index 2e2467e527aa4..a33fc8633af34 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-09-04 +date: 2024-09-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 3384b680d1e82..fc48272f266b4 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-09-04 +date: 2024-09-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 d1617a86e5a10..0c1cad74c6322 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index f49be2c77f004..afbfef74bcc5c 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-09-04 +date: 2024-09-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 7091f0cecdab3..956a20494b1a1 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-09-04 +date: 2024-09-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 946ae448c273a..c7c0069aa7f1a 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-09-04 +date: 2024-09-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 3fe39d7d87a97..5c47d041b882a 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-09-04 +date: 2024-09-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 503c0f260f597..9ca0433ba6dd8 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-09-04 +date: 2024-09-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 73dfb01f7878d..02e6f8a80aab3 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-09-04 +date: 2024-09-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 efd6ef775ebe9..f21aed205d96e 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-09-04 +date: 2024-09-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 7772a62d74e4b..0767cfe2107b5 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-09-04 +date: 2024-09-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 3a1257852b91a..3afd966c1d202 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-09-04 +date: 2024-09-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 0db6a0a524330..95dbb493ceaa8 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-09-04 +date: 2024-09-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 0e79aec2b7194..39515ced90cb3 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-09-04 +date: 2024-09-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 32d177185b23c..801c52b0e2852 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'contentManagement'] --- import contentManagementObj from './content_management.devdocs.json'; diff --git a/api_docs/controls.devdocs.json b/api_docs/controls.devdocs.json index 611780f983f52..fa81eb3778122 100644 --- a/api_docs/controls.devdocs.json +++ b/api_docs/controls.devdocs.json @@ -6600,7 +6600,7 @@ "section": "def-public.PublishingSubject", "text": "PublishingSubject" }, - "; untilInitialized: () => Promise; openAddDataControlFlyout: (options?: { controlInputTransform?: ", + "; untilInitialized: () => Promise; openAddDataControlFlyout: (settings?: { controlInputTransform?: ", { "pluginId": "controls", "scope": "common", @@ -6608,7 +6608,7 @@ "section": "def-common.ControlInputTransform", "text": "ControlInputTransform" }, - " | undefined; onSave?: (() => void) | undefined; } | undefined) => void; labelPosition: ", + " | undefined; } | undefined) => void; labelPosition: ", { "pluginId": "@kbn/presentation-publishing", "scope": "public", @@ -7790,6 +7790,130 @@ "common": { "classes": [], "functions": [ + { + "parentPluginId": "controls", + "id": "def-common.controlGroupInputToRawControlGroupAttributes", + "type": "Function", + "tags": [], + "label": "controlGroupInputToRawControlGroupAttributes", + "description": [], + "signature": [ + "(controlGroupInput: Omit<", + { + "pluginId": "controls", + "scope": "common", + "docId": "kibControlsPluginApi", + "section": "def-common.ControlGroupInput", + "text": "ControlGroupInput" + }, + ", \"id\">) => ", + { + "pluginId": "controls", + "scope": "common", + "docId": "kibControlsPluginApi", + "section": "def-common.RawControlGroupAttributes", + "text": "RawControlGroupAttributes" + } + ], + "path": "src/plugins/controls/common/control_group/control_group_persistence.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "controls", + "id": "def-common.controlGroupInputToRawControlGroupAttributes.$1", + "type": "Object", + "tags": [], + "label": "controlGroupInput", + "description": [], + "signature": [ + "Omit<", + { + "pluginId": "controls", + "scope": "common", + "docId": "kibControlsPluginApi", + "section": "def-common.ControlGroupInput", + "text": "ControlGroupInput" + }, + ", \"id\">" + ], + "path": "src/plugins/controls/common/control_group/control_group_persistence.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "controls", + "id": "def-common.generateNewControlIds", + "type": "Function", + "tags": [], + "label": "generateNewControlIds", + "description": [], + "signature": [ + "(controlGroupInput?: ", + { + "pluginId": "controls", + "scope": "common", + "docId": "kibControlsPluginApi", + "section": "def-common.PersistableControlGroupInput", + "text": "PersistableControlGroupInput" + }, + " | undefined) => { panels: ", + { + "pluginId": "controls", + "scope": "common", + "docId": "kibControlsPluginApi", + "section": "def-common.ControlsPanels", + "text": "ControlsPanels" + }, + "; chainingSystem: ", + { + "pluginId": "controls", + "scope": "common", + "docId": "kibControlsPluginApi", + "section": "def-common.ControlGroupChainingSystem", + "text": "ControlGroupChainingSystem" + }, + "; ignoreParentSettings?: ", + "ParentIgnoreSettings", + " | undefined; controlStyle: ", + "ControlStyle", + "; showApplySelections?: boolean | undefined; } | undefined" + ], + "path": "src/plugins/controls/common/control_group/control_group_persistence.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "controls", + "id": "def-common.generateNewControlIds.$1", + "type": "Object", + "tags": [], + "label": "controlGroupInput", + "description": [], + "signature": [ + { + "pluginId": "controls", + "scope": "common", + "docId": "kibControlsPluginApi", + "section": "def-common.PersistableControlGroupInput", + "text": "PersistableControlGroupInput" + }, + " | undefined" + ], + "path": "src/plugins/controls/common/control_group/control_group_persistence.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "controls", "id": "def-common.getDefaultControlGroupInput", diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index 70335885c2ebc..9056601e59ecf 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.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 | |-------------------|-----------|------------------------|-----------------| -| 390 | 0 | 381 | 28 | +| 394 | 0 | 385 | 28 | ## Client diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index c3fc284d460ef..ec4a973666e78 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'customIntegrations'] --- import customIntegrationsObj from './custom_integrations.devdocs.json'; diff --git a/api_docs/dashboard.devdocs.json b/api_docs/dashboard.devdocs.json index 072fece856c25..805e3041563a0 100644 --- a/api_docs/dashboard.devdocs.json +++ b/api_docs/dashboard.devdocs.json @@ -959,23 +959,15 @@ "section": "def-common.SerializableRecord", "text": "SerializableRecord" }, - ")[] | undefined; controlGroupState?: (Partial<", + ")[] | undefined; controlGroupInput?: ", { "pluginId": "controls", - "scope": "public", - "docId": "kibControlsPluginApi", - "section": "def-public.ControlGroupRuntimeState", - "text": "ControlGroupRuntimeState" - }, - "> & ", - { - "pluginId": "@kbn/utility-types", "scope": "common", - "docId": "kibKbnUtilityTypesPluginApi", - "section": "def-common.SerializableRecord", - "text": "SerializableRecord" + "docId": "kibControlsPluginApi", + "section": "def-common.SerializableControlGroupInput", + "text": "SerializableControlGroupInput" }, - ") | undefined; }" + " | undefined; }" ], "path": "src/plugins/dashboard/public/dashboard_container/types.ts", "deprecated": false, diff --git a/api_docs/dashboard.mdx b/api_docs/dashboard.mdx index a1dd7fbffa488..f4b8060e85085 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-09-04 +date: 2024-09-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 70353bbdd7ec3..130467e8f9c6a 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-09-04 +date: 2024-09-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 10e744b78da03..3c5e203e1f0b4 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; diff --git a/api_docs/data_quality.mdx b/api_docs/data_quality.mdx index 4e27a7f498fec..2a6c0b5dbf9c6 100644 --- a/api_docs/data_quality.mdx +++ b/api_docs/data_quality.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataQuality title: "dataQuality" image: https://source.unsplash.com/400x175/?github description: API docs for the dataQuality plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataQuality'] --- import dataQualityObj from './data_quality.devdocs.json'; diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index 02148f916ae5f..3e1bfac13f603 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-09-04 +date: 2024-09-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 c653d70c880ec..21ad6459d365c 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-09-04 +date: 2024-09-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 5b8784fe4e44e..09651de9b90c4 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-09-04 +date: 2024-09-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 1b68cca161294..d9406d662425d 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-09-04 +date: 2024-09-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 72c86cd07df14..5557828789af9 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-09-04 +date: 2024-09-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 219f59ba54762..7209b5c20ba32 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-09-04 +date: 2024-09-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 4718541aa1238..36d9efad46a86 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-09-04 +date: 2024-09-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 b80356f4f182d..6cc7b4b9af1ee 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-09-04 +date: 2024-09-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 8532d47a7c98c..b8769023fb338 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index b62a87242c1d4..6b99f787e9bf7 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -654,7 +654,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/data/types.ts#:~:text=fieldFormats), [data_service.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/data/data_service.ts#:~:text=fieldFormats) | - | | | [dashboard_grid_item.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx#:~:text=EmbeddablePanel), [dashboard_grid_item.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx#:~:text=EmbeddablePanel) | - | | | [plugin.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/plugin.tsx#:~:text=registerEmbeddableFactory) | - | -| | [migrate_dashboard_input.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.ts#:~:text=getEmbeddableFactory), [dashboard_container.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx#:~:text=getEmbeddableFactory), [dashboard_container.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx#:~:text=getEmbeddableFactory), [dashboard_renderer.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.tsx#:~:text=getEmbeddableFactory), [embeddable.stub.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/embeddable/embeddable.stub.ts#:~:text=getEmbeddableFactory), [create_dashboard.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts#:~:text=getEmbeddableFactory), [create_dashboard.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts#:~:text=getEmbeddableFactory), [create_dashboard.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts#:~:text=getEmbeddableFactory), [migrate_dashboard_input.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.test.ts#:~:text=getEmbeddableFactory), [migrate_dashboard_input.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.test.ts#:~:text=getEmbeddableFactory)+ 2 more | - | +| | [migrate_dashboard_input.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.ts#:~:text=getEmbeddableFactory), [migrate_dashboard_input.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.ts#:~:text=getEmbeddableFactory), [create_dashboard.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts#:~:text=getEmbeddableFactory), [dashboard_container.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx#:~:text=getEmbeddableFactory), [dashboard_container.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx#:~:text=getEmbeddableFactory), [dashboard_renderer.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.tsx#:~:text=getEmbeddableFactory), [embeddable.stub.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/embeddable/embeddable.stub.ts#:~:text=getEmbeddableFactory), [create_dashboard.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts#:~:text=getEmbeddableFactory), [create_dashboard.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts#:~:text=getEmbeddableFactory), [create_dashboard.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts#:~:text=getEmbeddableFactory)+ 9 more | - | | | [embeddable.stub.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/embeddable/embeddable.stub.ts#:~:text=getEmbeddableFactories), [embeddable.stub.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/embeddable/embeddable.stub.ts#:~:text=getEmbeddableFactories) | - | | | [save_modal.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/api/overlays/save_modal.tsx#:~:text=SavedObjectSaveModal), [save_modal.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/api/overlays/save_modal.tsx#:~:text=SavedObjectSaveModal), [add_to_library_action.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.tsx#:~:text=SavedObjectSaveModal), [add_to_library_action.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.tsx#:~:text=SavedObjectSaveModal) | 8.8.0 | | | [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/common/bwc/types.ts#:~:text=SavedObjectReference), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/common/bwc/types.ts#:~:text=SavedObjectReference) | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 3c7e127bad3f5..21fcad5b028e1 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index ea1f91be71d3d..5f4d0f97cecb7 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-09-04 +date: 2024-09-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 5164047390e41..eb843f172fc55 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-09-04 +date: 2024-09-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 1cfbf5169cc94..daf497f00c5df 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/discover_shared.mdx b/api_docs/discover_shared.mdx index ed2eb920a2f2e..abe209a5e769a 100644 --- a/api_docs/discover_shared.mdx +++ b/api_docs/discover_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverShared title: "discoverShared" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverShared plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverShared'] --- import discoverSharedObj from './discover_shared.devdocs.json'; diff --git a/api_docs/ecs_data_quality_dashboard.mdx b/api_docs/ecs_data_quality_dashboard.mdx index 295eef3ff67d2..2257c9b09c9a9 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-09-04 +date: 2024-09-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 44353f00a69ff..95d6a9cfbd6cf 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-09-04 +date: 2024-09-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 b48eddc9bd7a5..c4ac65a8b4ca6 100644 --- a/api_docs/embeddable.devdocs.json +++ b/api_docs/embeddable.devdocs.json @@ -9753,22 +9753,6 @@ "path": "src/plugins/embeddable/public/lib/containers/i_container.ts", "deprecated": false, "trackAdoption": false - }, - { - "parentPluginId": "embeddable", - "id": "def-public.EmbeddableContainerSettings.untilContainerInitialized", - "type": "Function", - "tags": [], - "label": "untilContainerInitialized", - "description": [], - "signature": [ - "(() => Promise) | undefined" - ], - "path": "src/plugins/embeddable/public/lib/containers/i_container.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] } ], "initialIsOpen": false @@ -13733,10 +13717,10 @@ "children": [ { "parentPluginId": "embeddable", - "id": "def-public.COMMON_EMBEDDABLE_GROUPING.legacy", + "id": "def-public.COMMON_EMBEDDABLE_GROUPING.annotation", "type": "Object", "tags": [], - "label": "legacy", + "label": "annotation", "description": [], "path": "src/plugins/embeddable/public/lib/embeddables/common/constants.ts", "deprecated": false, @@ -13744,7 +13728,7 @@ "children": [ { "parentPluginId": "embeddable", - "id": "def-public.COMMON_EMBEDDABLE_GROUPING.legacy.id", + "id": "def-public.COMMON_EMBEDDABLE_GROUPING.annotation.id", "type": "string", "tags": [], "label": "id", @@ -13755,7 +13739,7 @@ }, { "parentPluginId": "embeddable", - "id": "def-public.COMMON_EMBEDDABLE_GROUPING.legacy.getDisplayName", + "id": "def-public.COMMON_EMBEDDABLE_GROUPING.annotation.getDisplayName", "type": "Function", "tags": [], "label": "getDisplayName", @@ -13771,7 +13755,7 @@ }, { "parentPluginId": "embeddable", - "id": "def-public.COMMON_EMBEDDABLE_GROUPING.legacy.order", + "id": "def-public.COMMON_EMBEDDABLE_GROUPING.annotation.order", "type": "number", "tags": [], "label": "order", @@ -13784,10 +13768,10 @@ }, { "parentPluginId": "embeddable", - "id": "def-public.COMMON_EMBEDDABLE_GROUPING.annotation", + "id": "def-public.COMMON_EMBEDDABLE_GROUPING.other", "type": "Object", "tags": [], - "label": "annotation", + "label": "other", "description": [], "path": "src/plugins/embeddable/public/lib/embeddables/common/constants.ts", "deprecated": false, @@ -13795,7 +13779,7 @@ "children": [ { "parentPluginId": "embeddable", - "id": "def-public.COMMON_EMBEDDABLE_GROUPING.annotation.id", + "id": "def-public.COMMON_EMBEDDABLE_GROUPING.other.id", "type": "string", "tags": [], "label": "id", @@ -13806,7 +13790,7 @@ }, { "parentPluginId": "embeddable", - "id": "def-public.COMMON_EMBEDDABLE_GROUPING.annotation.getDisplayName", + "id": "def-public.COMMON_EMBEDDABLE_GROUPING.other.getDisplayName", "type": "Function", "tags": [], "label": "getDisplayName", @@ -13819,15 +13803,42 @@ "trackAdoption": false, "children": [], "returnComment": [] + }, + { + "parentPluginId": "embeddable", + "id": "def-public.COMMON_EMBEDDABLE_GROUPING.other.getIconType", + "type": "Function", + "tags": [], + "label": "getIconType", + "description": [], + "signature": [ + "() => string" + ], + "path": "src/plugins/embeddable/public/lib/embeddables/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "embeddable", + "id": "def-public.COMMON_EMBEDDABLE_GROUPING.other.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "src/plugins/embeddable/public/lib/embeddables/common/constants.ts", + "deprecated": false, + "trackAdoption": false } ] }, { "parentPluginId": "embeddable", - "id": "def-public.COMMON_EMBEDDABLE_GROUPING.other", + "id": "def-public.COMMON_EMBEDDABLE_GROUPING.legacy", "type": "Object", "tags": [], - "label": "other", + "label": "legacy", "description": [], "path": "src/plugins/embeddable/public/lib/embeddables/common/constants.ts", "deprecated": false, @@ -13835,7 +13846,7 @@ "children": [ { "parentPluginId": "embeddable", - "id": "def-public.COMMON_EMBEDDABLE_GROUPING.other.id", + "id": "def-public.COMMON_EMBEDDABLE_GROUPING.legacy.id", "type": "string", "tags": [], "label": "id", @@ -13846,7 +13857,7 @@ }, { "parentPluginId": "embeddable", - "id": "def-public.COMMON_EMBEDDABLE_GROUPING.other.getDisplayName", + "id": "def-public.COMMON_EMBEDDABLE_GROUPING.legacy.getDisplayName", "type": "Function", "tags": [], "label": "getDisplayName", @@ -13862,23 +13873,7 @@ }, { "parentPluginId": "embeddable", - "id": "def-public.COMMON_EMBEDDABLE_GROUPING.other.getIconType", - "type": "Function", - "tags": [], - "label": "getIconType", - "description": [], - "signature": [ - "() => string" - ], - "path": "src/plugins/embeddable/public/lib/embeddables/common/constants.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "embeddable", - "id": "def-public.COMMON_EMBEDDABLE_GROUPING.other.order", + "id": "def-public.COMMON_EMBEDDABLE_GROUPING.legacy.order", "type": "number", "tags": [], "label": "order", @@ -14860,6 +14855,14 @@ "plugin": "dashboard", "path": "src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.ts" }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.ts" + }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts" + }, { "plugin": "dashboard", "path": "src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx" @@ -14896,6 +14899,26 @@ "plugin": "dashboard", "path": "src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts" }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts" + }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts" + }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.test.ts" + }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.test.ts" + }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.test.ts" + }, { "plugin": "dashboard", "path": "src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.test.ts" diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index ca327b7c2a18a..e6a23ccc3d53c 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddable'] --- import embeddableObj from './embeddable.devdocs.json'; diff --git a/api_docs/embeddable_enhanced.mdx b/api_docs/embeddable_enhanced.mdx index 08bdf957acfa3..ed618b7ca26dc 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-09-04 +date: 2024-09-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 e736ec9e8d649..67f8d3c5d1cfc 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-09-04 +date: 2024-09-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 a3240347c7770..eeb5c139dab18 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/entities_data_access.mdx b/api_docs/entities_data_access.mdx index 5053e9568c28f..75398c54e5460 100644 --- a/api_docs/entities_data_access.mdx +++ b/api_docs/entities_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/entitiesDataAccess title: "entitiesDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the entitiesDataAccess plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'entitiesDataAccess'] --- import entitiesDataAccessObj from './entities_data_access.devdocs.json'; diff --git a/api_docs/entity_manager.mdx b/api_docs/entity_manager.mdx index ee7a315dc646b..83fc2f9610c28 100644 --- a/api_docs/entity_manager.mdx +++ b/api_docs/entity_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/entityManager title: "entityManager" image: https://source.unsplash.com/400x175/?github description: API docs for the entityManager plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'entityManager'] --- import entityManagerObj from './entity_manager.devdocs.json'; diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index 41d16c588457b..99246ea4f5438 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/esql.mdx b/api_docs/esql.mdx index 5b58ef9e07df4..e63f6dca8e3ea 100644 --- a/api_docs/esql.mdx +++ b/api_docs/esql.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esql title: "esql" image: https://source.unsplash.com/400x175/?github description: API docs for the esql plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esql'] --- import esqlObj from './esql.devdocs.json'; diff --git a/api_docs/esql_data_grid.mdx b/api_docs/esql_data_grid.mdx index 3925db5fbbab4..6ee745b003794 100644 --- a/api_docs/esql_data_grid.mdx +++ b/api_docs/esql_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esqlDataGrid title: "esqlDataGrid" image: https://source.unsplash.com/400x175/?github description: API docs for the esqlDataGrid plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esqlDataGrid'] --- import esqlDataGridObj from './esql_data_grid.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index b802c4fdaeb0c..3734d82e8e9d3 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-09-04 +date: 2024-09-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 78e00d45a90a6..c0faab5ebe496 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-09-04 +date: 2024-09-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 6602c3fe906d0..10440e6c04cae 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-09-04 +date: 2024-09-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 7ffccb4bed2f1..2ffaa3f07045c 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-09-04 +date: 2024-09-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 42f243dc0a492..37f1ffb23a58f 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-09-04 +date: 2024-09-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 e322b97ed85b0..5a62c26489a05 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-09-04 +date: 2024-09-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 0f27f4798fd01..be647fc063a52 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-09-04 +date: 2024-09-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 884f2111e4bf9..e1160d42f5279 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-09-04 +date: 2024-09-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 f517d844e4cd6..2605a6f2b41d3 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-09-04 +date: 2024-09-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 0f75d70c2e67f..eb9a9c4a44e79 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-09-04 +date: 2024-09-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 95d383edffdb0..7fd0cd4a42380 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-09-04 +date: 2024-09-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 c19eb03d70eab..eafabb45ab671 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-09-04 +date: 2024-09-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 cf4251f26b316..b21591fe64360 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-09-04 +date: 2024-09-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 b136f847e28d5..8453ee98830e9 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-09-04 +date: 2024-09-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 a38a63547b257..7de851a5208fc 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-09-04 +date: 2024-09-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 7a4a0138eb6ef..82a56661fc53a 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-09-04 +date: 2024-09-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 6af98937e04ea..264aa86b03555 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-09-04 +date: 2024-09-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 82fdf61b94248..90d813964c0a8 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-09-04 +date: 2024-09-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 0993e80d5766b..ad91cbd5ee0e7 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-09-04 +date: 2024-09-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 5ffb520b6ad7f..d3a66ae2dd474 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/fields_metadata.mdx b/api_docs/fields_metadata.mdx index 4d553af5d138c..c6bf76a5de583 100644 --- a/api_docs/fields_metadata.mdx +++ b/api_docs/fields_metadata.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldsMetadata title: "fieldsMetadata" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldsMetadata plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldsMetadata'] --- import fieldsMetadataObj from './fields_metadata.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index 7a74e83ab837e..eefc467b35ea4 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-09-04 +date: 2024-09-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 eaac1cbe4e941..f72c0b01da5cb 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-09-04 +date: 2024-09-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 1d9f8771d5b8f..9f9cdf1e0e207 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-09-04 +date: 2024-09-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 e3514a62f90f6..b718522f6fe6d 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-09-04 +date: 2024-09-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 aab1b754f5f35..5ebee384d33ff 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-09-04 +date: 2024-09-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 c6a9208f7468d..68a28613a0b1a 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-09-04 +date: 2024-09-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 0a1bd9d621145..870a26d182971 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-09-04 +date: 2024-09-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 f2bcd790a9808..8a887750647ea 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-09-04 +date: 2024-09-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 d777abb07c7a8..a5d7d28281a87 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-09-04 +date: 2024-09-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 eae9b32b5fc9d..7c00262434245 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/inference.devdocs.json b/api_docs/inference.devdocs.json index 642be486024c6..f3ad7f665a14c 100644 --- a/api_docs/inference.devdocs.json +++ b/api_docs/inference.devdocs.json @@ -62,15 +62,21 @@ "label": "chatComplete", "description": [], "signature": [ - "(options: { connectorId: string; system?: string | undefined; messages: ", - "Message", - "[]; } & ", + ") => ", - "ChatCompletionResponse", - "<", + " = ", "ToolOptions", - ">" + ">(options: { connectorId: string; system?: string | undefined; messages: ", + { + "pluginId": "inference", + "scope": "common", + "docId": "kibInferencePluginApi", + "section": "def-common.Message", + "text": "Message" + }, + "[]; } & TToolOptions) => ", + "ChatCompletionResponse", + "" ], "path": "x-pack/plugins/inference/public/types.ts", "deprecated": false, @@ -86,7 +92,13 @@ "description": [], "signature": [ "{ connectorId: string; system?: string | undefined; messages: ", - "Message", + { + "pluginId": "inference", + "scope": "common", + "docId": "kibInferencePluginApi", + "section": "def-common.Message", + "text": "Message" + }, "[]; } & TToolOptions" ], "path": "x-pack/plugins/inference/common/chat_complete/index.ts", @@ -103,7 +115,15 @@ "label": "output", "description": [], "signature": [ - "(id: TId, options: { connectorId: string; system?: string | undefined; input: string; schema?: TOutputSchema | undefined; }) => ", + "(id: TId, options: { connectorId: string; system?: string | undefined; input: string; schema?: TOutputSchema | undefined; previousMessages?: ", + { + "pluginId": "inference", + "scope": "common", + "docId": "kibInferencePluginApi", + "section": "def-common.Message", + "text": "Message" + }, + "[] | undefined; }) => ", "Observable", "<", "OutputEvent", @@ -138,7 +158,15 @@ "label": "options", "description": [], "signature": [ - "{ connectorId: string; system?: string | undefined; input: string; schema?: TOutputSchema | undefined; }" + "{ connectorId: string; system?: string | undefined; input: string; schema?: TOutputSchema | undefined; previousMessages?: ", + { + "pluginId": "inference", + "scope": "common", + "docId": "kibInferencePluginApi", + "section": "def-common.Message", + "text": "Message" + }, + "[] | undefined; }" ], "path": "x-pack/plugins/inference/common/output/index.ts", "deprecated": false, @@ -172,6 +200,77 @@ "server": { "classes": [], "functions": [ + { + "parentPluginId": "inference", + "id": "def-server.naturalLanguageToEsql", + "type": "Function", + "tags": [], + "label": "naturalLanguageToEsql", + "description": [], + "signature": [ + "({\n client,\n connectorId,\n tools,\n toolChoice,\n logger,\n ...rest\n}: { client: Pick<", + "InferenceClient", + ", \"output\" | \"chatComplete\">; connectorId: string; logger: Pick<", + { + "pluginId": "@kbn/logging", + "scope": "common", + "docId": "kibKbnLoggingPluginApi", + "section": "def-common.Logger", + "text": "Logger" + }, + ", \"debug\">; } & TToolOptions & ({ input: string; } | { messages: ", + { + "pluginId": "inference", + "scope": "common", + "docId": "kibInferencePluginApi", + "section": "def-common.Message", + "text": "Message" + }, + "[]; })) => ", + "Observable", + ">" + ], + "path": "x-pack/plugins/inference/server/tasks/nl_to_esql/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "inference", + "id": "def-server.naturalLanguageToEsql.$1", + "type": "CompoundType", + "tags": [], + "label": "{\n client,\n connectorId,\n tools,\n toolChoice,\n logger,\n ...rest\n}", + "description": [], + "signature": [ + "{ client: Pick<", + "InferenceClient", + ", \"output\" | \"chatComplete\">; connectorId: string; logger: Pick<", + { + "pluginId": "@kbn/logging", + "scope": "common", + "docId": "kibKbnLoggingPluginApi", + "section": "def-common.Logger", + "text": "Logger" + }, + ", \"debug\">; } & TToolOptions & ({ input: string; } | { messages: ", + { + "pluginId": "inference", + "scope": "common", + "docId": "kibInferencePluginApi", + "section": "def-common.Message", + "text": "Message" + }, + "[]; })" + ], + "path": "x-pack/plugins/inference/server/tasks/nl_to_esql/index.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "inference", "id": "def-server.withoutChunkEvents", @@ -309,10 +408,447 @@ }, "common": { "classes": [], - "functions": [], + "functions": [ + { + "parentPluginId": "inference", + "id": "def-common.correctCommonEsqlMistakes", + "type": "Function", + "tags": [], + "label": "correctCommonEsqlMistakes", + "description": [], + "signature": [ + "(query: string) => { isCorrection: boolean; input: string; output: string; }" + ], + "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "inference", + "id": "def-common.correctCommonEsqlMistakes.$1", + "type": "string", + "tags": [], + "label": "query", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "inference", + "id": "def-common.generateFakeToolCallId", + "type": "Function", + "tags": [], + "label": "generateFakeToolCallId", + "description": [], + "signature": [ + "() => string" + ], + "path": "x-pack/plugins/inference/common/chat_complete/generate_fake_tool_call_id.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "inference", + "id": "def-common.isChatCompletionChunkEvent", + "type": "Function", + "tags": [], + "label": "isChatCompletionChunkEvent", + "description": [], + "signature": [ + "(event: ", + "ChatCompletionEvent", + "<", + "ToolOptions", + ">) => boolean" + ], + "path": "x-pack/plugins/inference/common/chat_complete/is_chat_completion_chunk_event.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "inference", + "id": "def-common.isChatCompletionChunkEvent.$1", + "type": "CompoundType", + "tags": [], + "label": "event", + "description": [], + "signature": [ + "ChatCompletionEvent", + "<", + "ToolOptions", + ">" + ], + "path": "x-pack/plugins/inference/common/chat_complete/is_chat_completion_chunk_event.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "inference", + "id": "def-common.isChatCompletionEvent", + "type": "Function", + "tags": [], + "label": "isChatCompletionEvent", + "description": [], + "signature": [ + "(event: ", + "InferenceTaskEvent", + ") => boolean" + ], + "path": "x-pack/plugins/inference/common/chat_complete/is_chat_completion_event.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "inference", + "id": "def-common.isChatCompletionEvent.$1", + "type": "Object", + "tags": [], + "label": "event", + "description": [], + "signature": [ + "InferenceTaskEvent" + ], + "path": "x-pack/plugins/inference/common/chat_complete/is_chat_completion_event.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "inference", + "id": "def-common.isChatCompletionMessageEvent", + "type": "Function", + "tags": [], + "label": "isChatCompletionMessageEvent", + "description": [], + "signature": [ + "(event: ", + "ChatCompletionEvent", + ") => boolean" + ], + "path": "x-pack/plugins/inference/common/chat_complete/is_chat_completion_message_event.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "inference", + "id": "def-common.isChatCompletionMessageEvent.$1", + "type": "CompoundType", + "tags": [], + "label": "event", + "description": [], + "signature": [ + "ChatCompletionEvent", + "" + ], + "path": "x-pack/plugins/inference/common/chat_complete/is_chat_completion_message_event.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "inference", + "id": "def-common.isOutputCompleteEvent", + "type": "Function", + "tags": [], + "label": "isOutputCompleteEvent", + "description": [], + "signature": [ + "(event: TOutputEvent) => boolean" + ], + "path": "x-pack/plugins/inference/common/output/is_output_complete_event.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "inference", + "id": "def-common.isOutputCompleteEvent.$1", + "type": "Uncategorized", + "tags": [], + "label": "event", + "description": [], + "signature": [ + "TOutputEvent" + ], + "path": "x-pack/plugins/inference/common/output/is_output_complete_event.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "inference", + "id": "def-common.isOutputEvent", + "type": "Function", + "tags": [], + "label": "isOutputEvent", + "description": [], + "signature": [ + "(event: ", + "InferenceTaskEvent", + ") => boolean" + ], + "path": "x-pack/plugins/inference/common/output/is_output_event.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "inference", + "id": "def-common.isOutputEvent.$1", + "type": "Object", + "tags": [], + "label": "event", + "description": [], + "signature": [ + "InferenceTaskEvent" + ], + "path": "x-pack/plugins/inference/common/output/is_output_event.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "inference", + "id": "def-common.isOutputUpdateEvent", + "type": "Function", + "tags": [], + "label": "isOutputUpdateEvent", + "description": [], + "signature": [ + "(event: ", + "OutputEvent", + ") => boolean" + ], + "path": "x-pack/plugins/inference/common/output/is_output_update_event.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "inference", + "id": "def-common.isOutputUpdateEvent.$1", + "type": "CompoundType", + "tags": [], + "label": "event", + "description": [], + "signature": [ + "OutputEvent", + "" + ], + "path": "x-pack/plugins/inference/common/output/is_output_update_event.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "inference", + "id": "def-common.splitIntoCommands", + "type": "Function", + "tags": [], + "label": "splitIntoCommands", + "description": [], + "signature": [ + "(query: string) => { name: string | undefined; command: string; }[]" + ], + "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "inference", + "id": "def-common.splitIntoCommands.$1", + "type": "string", + "tags": [], + "label": "query", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], "interfaces": [], - "enums": [], - "misc": [], + "enums": [ + { + "parentPluginId": "inference", + "id": "def-common.MessageRole", + "type": "Enum", + "tags": [], + "label": "MessageRole", + "description": [], + "path": "x-pack/plugins/inference/common/chat_complete/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "misc": [ + { + "parentPluginId": "inference", + "id": "def-common.AssistantMessage", + "type": "Type", + "tags": [], + "label": "AssistantMessage", + "description": [], + "signature": [ + "MessageBase<", + { + "pluginId": "inference", + "scope": "common", + "docId": "kibInferencePluginApi", + "section": "def-common.MessageRole", + "text": "MessageRole" + }, + ".Assistant> & { content: string | null; toolCalls?: ", + "ToolCall", + " | undefined>[] | undefined; }" + ], + "path": "x-pack/plugins/inference/common/chat_complete/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "inference", + "id": "def-common.Message", + "type": "Type", + "tags": [], + "label": "Message", + "description": [], + "signature": [ + { + "pluginId": "inference", + "scope": "common", + "docId": "kibInferencePluginApi", + "section": "def-common.UserMessage", + "text": "UserMessage" + }, + " | ", + { + "pluginId": "inference", + "scope": "common", + "docId": "kibInferencePluginApi", + "section": "def-common.AssistantMessage", + "text": "AssistantMessage" + }, + " | ", + { + "pluginId": "inference", + "scope": "common", + "docId": "kibInferencePluginApi", + "section": "def-common.ToolMessage", + "text": "ToolMessage" + }, + "" + ], + "path": "x-pack/plugins/inference/common/chat_complete/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "inference", + "id": "def-common.ToolMessage", + "type": "Type", + "tags": [], + "label": "ToolMessage", + "description": [], + "signature": [ + "MessageBase<", + { + "pluginId": "inference", + "scope": "common", + "docId": "kibInferencePluginApi", + "section": "def-common.MessageRole", + "text": "MessageRole" + }, + ".Tool> & { toolCallId: string; response: TToolResponse; }" + ], + "path": "x-pack/plugins/inference/common/chat_complete/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "inference", + "id": "def-common.ToolSchema", + "type": "Type", + "tags": [], + "label": "ToolSchema", + "description": [], + "signature": [ + "ToolSchemaTypeObject" + ], + "path": "x-pack/plugins/inference/common/chat_complete/tool_schema.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "inference", + "id": "def-common.UserMessage", + "type": "Type", + "tags": [], + "label": "UserMessage", + "description": [], + "signature": [ + "MessageBase<", + { + "pluginId": "inference", + "scope": "common", + "docId": "kibInferencePluginApi", + "section": "def-common.MessageRole", + "text": "MessageRole" + }, + ".User> & { content: string; }" + ], + "path": "x-pack/plugins/inference/common/chat_complete/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], "objects": [] } } \ No newline at end of file diff --git a/api_docs/inference.mdx b/api_docs/inference.mdx index 37600fc7c5c2a..91d2efcb9bc67 100644 --- a/api_docs/inference.mdx +++ b/api_docs/inference.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inference title: "inference" image: https://source.unsplash.com/400x175/?github description: API docs for the inference plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inference'] --- import inferenceObj from './inference.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 16 | 0 | 14 | 11 | +| 41 | 0 | 39 | 13 | ## Client @@ -45,3 +45,14 @@ Contact [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai ### Functions +## Common + +### Functions + + +### Enums + + +### Consts, variables and types + + diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index bd72b6333769f..2217593593b77 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-09-04 +date: 2024-09-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 7ac2dcfb4ecd0..c039facb9f39d 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-09-04 +date: 2024-09-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 7e5fb612e2868..35e358f0e8d35 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/integration_assistant.mdx b/api_docs/integration_assistant.mdx index 385a15fda876d..6309e353c9572 100644 --- a/api_docs/integration_assistant.mdx +++ b/api_docs/integration_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/integrationAssistant title: "integrationAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the integrationAssistant plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'integrationAssistant'] --- import integrationAssistantObj from './integration_assistant.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index 612b0bf3967e3..86741fcbed4b9 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/investigate.mdx b/api_docs/investigate.mdx index a4a135461cf8e..98f2a809f41b1 100644 --- a/api_docs/investigate.mdx +++ b/api_docs/investigate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/investigate title: "investigate" image: https://source.unsplash.com/400x175/?github description: API docs for the investigate plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'investigate'] --- import investigateObj from './investigate.devdocs.json'; diff --git a/api_docs/investigate_app.mdx b/api_docs/investigate_app.mdx index 3dadfb125ac44..6f04af420aa24 100644 --- a/api_docs/investigate_app.mdx +++ b/api_docs/investigate_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/investigateApp title: "investigateApp" image: https://source.unsplash.com/400x175/?github description: API docs for the investigateApp plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'investigateApp'] --- import investigateAppObj from './investigate_app.devdocs.json'; diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index 559b84f7c7b0c..a18fc8f80c58c 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-09-04 +date: 2024-09-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 0430dd0ff009b..bf644bb2691bc 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-09-04 +date: 2024-09-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 9ac9be5e16de7..b73c3614c227b 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; diff --git a/api_docs/kbn_aiops_log_pattern_analysis.mdx b/api_docs/kbn_aiops_log_pattern_analysis.mdx index c135ea04c7538..bf7db97d06016 100644 --- a/api_docs/kbn_aiops_log_pattern_analysis.mdx +++ b/api_docs/kbn_aiops_log_pattern_analysis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-log-pattern-analysis title: "@kbn/aiops-log-pattern-analysis" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-log-pattern-analysis plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-log-pattern-analysis'] --- import kbnAiopsLogPatternAnalysisObj from './kbn_aiops_log_pattern_analysis.devdocs.json'; diff --git a/api_docs/kbn_aiops_log_rate_analysis.mdx b/api_docs/kbn_aiops_log_rate_analysis.mdx index 7408afbd8bee9..7d629a882f469 100644 --- a/api_docs/kbn_aiops_log_rate_analysis.mdx +++ b/api_docs/kbn_aiops_log_rate_analysis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-log-rate-analysis title: "@kbn/aiops-log-rate-analysis" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-log-rate-analysis plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-log-rate-analysis'] --- import kbnAiopsLogRateAnalysisObj from './kbn_aiops_log_rate_analysis.devdocs.json'; diff --git a/api_docs/kbn_alerting_api_integration_helpers.mdx b/api_docs/kbn_alerting_api_integration_helpers.mdx index 99fffbc22e03f..1ef7f8de25048 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-09-04 +date: 2024-09-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_comparators.mdx b/api_docs/kbn_alerting_comparators.mdx index 630ffdc3118b8..06b6c3db61ddd 100644 --- a/api_docs/kbn_alerting_comparators.mdx +++ b/api_docs/kbn_alerting_comparators.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-comparators title: "@kbn/alerting-comparators" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-comparators plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-comparators'] --- import kbnAlertingComparatorsObj from './kbn_alerting_comparators.devdocs.json'; diff --git a/api_docs/kbn_alerting_state_types.mdx b/api_docs/kbn_alerting_state_types.mdx index 23eda69ed8744..99fa58d326480 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-09-04 +date: 2024-09-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 f1d3606ee746c..25f0c57a7c6a4 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-09-04 +date: 2024-09-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 50b620bec389a..b73c504e2ffee 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-09-04 +date: 2024-09-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_grouping.mdx b/api_docs/kbn_alerts_grouping.mdx index b01845dbcfe4d..c70e06c886453 100644 --- a/api_docs/kbn_alerts_grouping.mdx +++ b/api_docs/kbn_alerts_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-grouping title: "@kbn/alerts-grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-grouping plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-grouping'] --- import kbnAlertsGroupingObj from './kbn_alerts_grouping.devdocs.json'; diff --git a/api_docs/kbn_alerts_ui_shared.mdx b/api_docs/kbn_alerts_ui_shared.mdx index aef34a61a447c..a5003d81ac8d5 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-09-04 +date: 2024-09-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 f3dc0513d3bc9..5b6d10b1b2b55 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_collection_utils.mdx b/api_docs/kbn_analytics_collection_utils.mdx index 48185cc463460..17df1d80a420e 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-09-04 +date: 2024-09-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_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index f1c2410251285..480126cf27478 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-09-04 +date: 2024-09-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_data_view.mdx b/api_docs/kbn_apm_data_view.mdx index 405dc244233ea..2af8921168f54 100644 --- a/api_docs/kbn_apm_data_view.mdx +++ b/api_docs/kbn_apm_data_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-data-view title: "@kbn/apm-data-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-data-view plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-data-view'] --- import kbnApmDataViewObj from './kbn_apm_data_view.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace.devdocs.json b/api_docs/kbn_apm_synthtrace.devdocs.json index 3c806005b1463..288c90fb48d62 100644 --- a/api_docs/kbn_apm_synthtrace.devdocs.json +++ b/api_docs/kbn_apm_synthtrace.devdocs.json @@ -894,6 +894,77 @@ } ], "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.SyntheticsSynthtraceEsClient", + "type": "Class", + "tags": [], + "label": "SyntheticsSynthtraceEsClient", + "description": [], + "signature": [ + { + "pluginId": "@kbn/apm-synthtrace", + "scope": "server", + "docId": "kibKbnApmSynthtracePluginApi", + "section": "def-server.SyntheticsSynthtraceEsClient", + "text": "SyntheticsSynthtraceEsClient" + }, + " extends ", + "SynthtraceEsClient", + "<", + { + "pluginId": "@kbn/apm-synthtrace-client", + "scope": "common", + "docId": "kibKbnApmSynthtraceClientPluginApi", + "section": "def-common.SyntheticsMonitorDocument", + "text": "SyntheticsMonitorDocument" + }, + ">" + ], + "path": "packages/kbn-apm-synthtrace/src/lib/synthetics/synthetics_synthtrace_es_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.SyntheticsSynthtraceEsClient.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-apm-synthtrace/src/lib/synthetics/synthetics_synthtrace_es_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.SyntheticsSynthtraceEsClient.Unnamed.$1", + "type": "CompoundType", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "{ client: ", + "default", + "; logger: ", + "Logger", + "; } & ", + "SyntheticsSynthtraceEsClientOptions" + ], + "path": "packages/kbn-apm-synthtrace/src/lib/synthetics/synthetics_synthtrace_es_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false } ], "functions": [ diff --git a/api_docs/kbn_apm_synthtrace.mdx b/api_docs/kbn_apm_synthtrace.mdx index 2f8bf7bf44ac2..17a8915c22a62 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/te | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 56 | 0 | 56 | 9 | +| 59 | 0 | 59 | 10 | ## Server diff --git a/api_docs/kbn_apm_synthtrace_client.devdocs.json b/api_docs/kbn_apm_synthtrace_client.devdocs.json index 94fa78faa93a5..e33639e0aa425 100644 --- a/api_docs/kbn_apm_synthtrace_client.devdocs.json +++ b/api_docs/kbn_apm_synthtrace_client.devdocs.json @@ -2780,6 +2780,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/apm-synthtrace-client", + "id": "def-common.SyntheticsMonitorDocument", + "type": "Type", + "tags": [], + "label": "SyntheticsMonitorDocument", + "description": [], + "signature": [ + "{ '@timestamp'?: number | undefined; } & Partial<{ 'data_stream.namespace': string; 'data_stream.type': string; 'data_stream.dataset': string; 'monitor.id': string; 'monitor.origin': string; 'monitor.name': string; 'monitor.type': string; 'monitor.check_group': string; 'monitor.timespan.lt': string; 'monitor.timespan.gte': string; 'monitor.duration.us'?: number | undefined; 'monitor.ip'?: string | undefined; 'monitor.project.name'?: string | undefined; 'monitor.project.id'?: string | undefined; 'monitor.fleet_managed'?: boolean | undefined; 'monitor.status'?: string | undefined; 'synthetics.type'?: string | undefined; 'synthetics.step.index'?: number | undefined; 'observer.os.name'?: string | undefined; 'observer.product'?: string | undefined; }>" + ], + "path": "packages/kbn-apm-synthtrace-client/src/lib/synthetics/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/apm-synthtrace-client", "id": "def-common.SynthtraceESAction", @@ -3344,6 +3359,36 @@ } ], "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/apm-synthtrace-client", + "id": "def-common.syntheticsMonitor", + "type": "Object", + "tags": [], + "label": "syntheticsMonitor", + "description": [], + "path": "packages/kbn-apm-synthtrace-client/src/lib/synthetics/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/apm-synthtrace-client", + "id": "def-common.syntheticsMonitor.create", + "type": "Function", + "tags": [], + "label": "create", + "description": [], + "signature": [ + "() => SyntheticsMonitor" + ], + "path": "packages/kbn-apm-synthtrace-client/src/lib/synthetics/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + } + ], + "initialIsOpen": false } ] } diff --git a/api_docs/kbn_apm_synthtrace_client.mdx b/api_docs/kbn_apm_synthtrace_client.mdx index fcb127d8e0ec9..c7dd01bd2fd29 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace-client'] --- import kbnApmSynthtraceClientObj from './kbn_apm_synthtrace_client.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/te | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 205 | 0 | 205 | 33 | +| 208 | 0 | 208 | 33 | ## Common diff --git a/api_docs/kbn_apm_types.mdx b/api_docs/kbn_apm_types.mdx index 1f83f24cfa16f..3baba11941894 100644 --- a/api_docs/kbn_apm_types.mdx +++ b/api_docs/kbn_apm_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-types title: "@kbn/apm-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-types plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-types'] --- import kbnApmTypesObj from './kbn_apm_types.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index 279bb6b44de93..18be7d36856ef 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_avc_banner.mdx b/api_docs/kbn_avc_banner.mdx index cb9e2c5cd0b8f..5249046c0e70e 100644 --- a/api_docs/kbn_avc_banner.mdx +++ b/api_docs/kbn_avc_banner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-avc-banner title: "@kbn/avc-banner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/avc-banner plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/avc-banner'] --- import kbnAvcBannerObj from './kbn_avc_banner.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index e94548a4ccb27..b70d7d56b7086 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-09-04 +date: 2024-09-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 20471029bed9c..a0f55f29d549b 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-09-04 +date: 2024-09-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 08a7da5344934..b6c96bc376143 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-09-04 +date: 2024-09-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 efdf3da767da4..45ee469400b2d 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-09-04 +date: 2024-09-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 8697c3a471d24..f650b0c33466c 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cases-components'] --- import kbnCasesComponentsObj from './kbn_cases_components.devdocs.json'; diff --git a/api_docs/kbn_cbor.mdx b/api_docs/kbn_cbor.mdx index 0a5e0e2723943..418112b5981f1 100644 --- a/api_docs/kbn_cbor.mdx +++ b/api_docs/kbn_cbor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cbor title: "@kbn/cbor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cbor plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cbor'] --- import kbnCborObj from './kbn_cbor.devdocs.json'; diff --git a/api_docs/kbn_cell_actions.mdx b/api_docs/kbn_cell_actions.mdx index c8051ffc266f1..5da53872389c3 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-09-04 +date: 2024-09-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 6c75269ce887b..86f63b2ff148b 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-09-04 +date: 2024-09-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 0e38e558527a5..eb9d06ade8fa4 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-09-04 +date: 2024-09-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 0a380ef725711..08b72485329ab 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-09-04 +date: 2024-09-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 24a5868c040bb..71e7873ef5cd7 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-09-04 +date: 2024-09-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 d073a89194abf..83f1c543068a4 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-09-04 +date: 2024-09-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 51d2d3ca4eb93..38a00acb02fb1 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-09-04 +date: 2024-09-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_cloud_security_posture.mdx b/api_docs/kbn_cloud_security_posture.mdx index 792d5e935e42b..16837db24176a 100644 --- a/api_docs/kbn_cloud_security_posture.mdx +++ b/api_docs/kbn_cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cloud-security-posture title: "@kbn/cloud-security-posture" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cloud-security-posture plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cloud-security-posture'] --- import kbnCloudSecurityPostureObj from './kbn_cloud_security_posture.devdocs.json'; diff --git a/api_docs/kbn_cloud_security_posture_common.devdocs.json b/api_docs/kbn_cloud_security_posture_common.devdocs.json index 854d90ed1a0f0..ae15a9e184a71 100644 --- a/api_docs/kbn_cloud_security_posture_common.devdocs.json +++ b/api_docs/kbn_cloud_security_posture_common.devdocs.json @@ -19,6 +19,54 @@ "common": { "classes": [], "functions": [ + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildEntityFlyoutPreviewQuery", + "type": "Function", + "tags": [], + "label": "buildEntityFlyoutPreviewQuery", + "description": [], + "signature": [ + "(field: string, queryValue?: string | undefined) => { bool: { filter: { bool: { should: { term: { [x: string]: { value: string; }; }; }[]; minimum_should_match: number; }; }[]; }; }" + ], + "path": "x-pack/packages/kbn-cloud-security-posture-common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildEntityFlyoutPreviewQuery.$1", + "type": "string", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/kbn-cloud-security-posture-common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildEntityFlyoutPreviewQuery.$2", + "type": "string", + "tags": [], + "label": "queryValue", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture-common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/cloud-security-posture-common", "id": "def-common.buildMutedRulesFilter", diff --git a/api_docs/kbn_cloud_security_posture_common.mdx b/api_docs/kbn_cloud_security_posture_common.mdx index 701cae6f345c8..68711028e8df6 100644 --- a/api_docs/kbn_cloud_security_posture_common.mdx +++ b/api_docs/kbn_cloud_security_posture_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cloud-security-posture-common title: "@kbn/cloud-security-posture-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cloud-security-posture-common plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cloud-security-posture-common'] --- import kbnCloudSecurityPostureCommonObj from './kbn_cloud_security_posture_common.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 49 | 0 | 49 | 0 | +| 52 | 0 | 52 | 0 | ## Common diff --git a/api_docs/kbn_code_editor.mdx b/api_docs/kbn_code_editor.mdx index aff2682776629..2a630ba68095b 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor'] --- import kbnCodeEditorObj from './kbn_code_editor.devdocs.json'; diff --git a/api_docs/kbn_code_editor_mock.mdx b/api_docs/kbn_code_editor_mock.mdx index 4ddc18f8e23f9..f5ac56c36bc7a 100644 --- a/api_docs/kbn_code_editor_mock.mdx +++ b/api_docs/kbn_code_editor_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor-mock title: "@kbn/code-editor-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor-mock plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor-mock'] --- import kbnCodeEditorMockObj from './kbn_code_editor_mock.devdocs.json'; diff --git a/api_docs/kbn_code_owners.mdx b/api_docs/kbn_code_owners.mdx index 18e8b2176b1d5..e24249f21374b 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-09-04 +date: 2024-09-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 8880044e759f9..befaab1025ea7 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-09-04 +date: 2024-09-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 f4ea8de69b132..bb2021e54be94 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-09-04 +date: 2024-09-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 724fdf9db7a2a..145b9f62d049a 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-09-04 +date: 2024-09-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 331cbf796fd67..d90b032979908 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-09-04 +date: 2024-09-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 9a812ddbd21ee..377dccdc93b00 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-09-04 +date: 2024-09-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_content_insights_public.mdx b/api_docs/kbn_content_management_content_insights_public.mdx index f3ab445f10c3f..a85ea7719023b 100644 --- a/api_docs/kbn_content_management_content_insights_public.mdx +++ b/api_docs/kbn_content_management_content_insights_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-insights-public title: "@kbn/content-management-content-insights-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-insights-public plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-insights-public'] --- import kbnContentManagementContentInsightsPublicObj from './kbn_content_management_content_insights_public.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_insights_server.mdx b/api_docs/kbn_content_management_content_insights_server.mdx index 8f90f672b2d6d..8e9e7ec6fafea 100644 --- a/api_docs/kbn_content_management_content_insights_server.mdx +++ b/api_docs/kbn_content_management_content_insights_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-insights-server title: "@kbn/content-management-content-insights-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-insights-server plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-insights-server'] --- import kbnContentManagementContentInsightsServerObj from './kbn_content_management_content_insights_server.devdocs.json'; diff --git a/api_docs/kbn_content_management_favorites_public.mdx b/api_docs/kbn_content_management_favorites_public.mdx index ba4c19a325528..37e4e9f494368 100644 --- a/api_docs/kbn_content_management_favorites_public.mdx +++ b/api_docs/kbn_content_management_favorites_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-favorites-public title: "@kbn/content-management-favorites-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-favorites-public plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-favorites-public'] --- import kbnContentManagementFavoritesPublicObj from './kbn_content_management_favorites_public.devdocs.json'; diff --git a/api_docs/kbn_content_management_favorites_server.mdx b/api_docs/kbn_content_management_favorites_server.mdx index 86c290aeb347e..aa6efdddebf3c 100644 --- a/api_docs/kbn_content_management_favorites_server.mdx +++ b/api_docs/kbn_content_management_favorites_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-favorites-server title: "@kbn/content-management-favorites-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-favorites-server plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-favorites-server'] --- import kbnContentManagementFavoritesServerObj from './kbn_content_management_favorites_server.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 7f74f65192d42..06e04209a3de1 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-09-04 +date: 2024-09-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 0da2d661d111d..9338277d74679 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-09-04 +date: 2024-09-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 3f1a1d48170db..95fe2876b2ea3 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-09-04 +date: 2024-09-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 22d517f7bafc8..065c22db5d5a3 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-09-04 +date: 2024-09-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_user_profiles.mdx b/api_docs/kbn_content_management_user_profiles.mdx index e66ea0de67df4..d892797104aeb 100644 --- a/api_docs/kbn_content_management_user_profiles.mdx +++ b/api_docs/kbn_content_management_user_profiles.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-user-profiles title: "@kbn/content-management-user-profiles" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-user-profiles plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-user-profiles'] --- import kbnContentManagementUserProfilesObj from './kbn_content_management_user_profiles.devdocs.json'; diff --git a/api_docs/kbn_content_management_utils.mdx b/api_docs/kbn_content_management_utils.mdx index 7bfc1826263d9..140913b0f72fb 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-09-04 +date: 2024-09-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 0ef602e7ecd61..ad66600d62c6d 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-09-04 +date: 2024-09-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 73a750a28aee9..c5d3860d5065c 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-09-04 +date: 2024-09-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 ec8425b7ccaa5..72a9b912b465f 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-09-04 +date: 2024-09-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 a6bef083e2143..5dd36f1473b29 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-09-04 +date: 2024-09-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 51a21430602e1..9f694028b13e9 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-09-04 +date: 2024-09-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 aedf82955bc87..47189eb0a3213 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-09-04 +date: 2024-09-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 08b390dbad8b0..c7d366880265e 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-09-04 +date: 2024-09-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 344e1585a8b31..21f1f2d570eec 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-09-04 +date: 2024-09-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 b7cfc11dd5881..7b3138c4d0fcf 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-09-04 +date: 2024-09-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 fd263d0da0243..3fbe3bab6e2e5 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-09-04 +date: 2024-09-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 a26f39e580c14..e42d9a063c0ea 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-09-04 +date: 2024-09-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 ee897cccf0a9f..26a0458580f1f 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-09-04 +date: 2024-09-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 d5859ccc33f09..06b4c1ac596f5 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-09-04 +date: 2024-09-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 ca25863d9612e..fabc7413a8278 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-09-04 +date: 2024-09-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 9ea4d7d3c4970..e741f026390b2 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-09-04 +date: 2024-09-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 ab224b821bec6..f743d2c14fd0c 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-09-04 +date: 2024-09-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 ef93d0899ca91..3e43de00d9401 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-09-04 +date: 2024-09-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 6596f50dc4db1..292e8400be145 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-09-04 +date: 2024-09-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 7c22798c5785b..6b99ebc53481c 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-09-04 +date: 2024-09-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 36c34d2a56bd8..dbf684cb8fc4b 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-09-04 +date: 2024-09-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 7c3db61aa23a2..7eea142874ccb 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-09-04 +date: 2024-09-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 cc790f9c12ab0..af0812f4fa489 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-09-04 +date: 2024-09-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 4fcf194c7d6f1..3132af991dec0 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-09-04 +date: 2024-09-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 f5ae9aa1caa4d..edbf15af08327 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-09-04 +date: 2024-09-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 ebb4df5788432..3e626d9195a01 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-09-04 +date: 2024-09-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 310007143d8d6..c6f80f566d631 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-09-04 +date: 2024-09-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 5581104e64345..34e988790069d 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-09-04 +date: 2024-09-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 74d1d6c119109..18fb06c42a46a 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-09-04 +date: 2024-09-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 faba4717db97b..f9df8b42456c7 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-09-04 +date: 2024-09-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 c5b804958b60e..49252a9d63c4d 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-09-04 +date: 2024-09-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 9a5ef43e8a7c3..d5adf78659c9c 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-09-04 +date: 2024-09-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 528623370d127..881b50943c70d 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-09-04 +date: 2024-09-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 f5c02b5b67ca3..5b43bd077e0ad 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-09-04 +date: 2024-09-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 6b1153087b658..e98d5dcbb9cbf 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-09-04 +date: 2024-09-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 1c99699305989..0bed39d4ed1c8 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-09-04 +date: 2024-09-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 3895b1b576bfd..8bb81fcf71228 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-09-04 +date: 2024-09-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 f974f19958e31..68917bce1d7e5 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-09-04 +date: 2024-09-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 989d33def0047..4dbacfb396fba 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-09-04 +date: 2024-09-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 0a9f15e852610..5e9e026449bc5 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-09-04 +date: 2024-09-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 fa7739b740f6e..e1a3d083e3ba0 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-09-04 +date: 2024-09-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 46c9c0384fdd6..38c4fd6e61baf 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-09-04 +date: 2024-09-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 f5f2d338b27f8..e8749fecb07cd 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-09-04 +date: 2024-09-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 5eb26fb820ade..215a800a9d674 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-09-04 +date: 2024-09-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 2d63c31c73d26..c8eafed5d7433 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-09-04 +date: 2024-09-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.devdocs.json b/api_docs/kbn_core_elasticsearch_server.devdocs.json index be09c9b65cbd1..3545ca05a5d0a 100644 --- a/api_docs/kbn_core_elasticsearch_server.devdocs.json +++ b/api_docs/kbn_core_elasticsearch_server.devdocs.json @@ -804,6 +804,22 @@ "path": "packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_service.test.ts" } ] + }, + { + "parentPluginId": "@kbn/core-elasticsearch-server", + "id": "def-server.ElasticsearchServiceSetup.publicBaseUrl", + "type": "string", + "tags": [], + "label": "publicBaseUrl", + "description": [ + "\nThe public base URL (if any) that should be used by end users to access the Elasticsearch cluster." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/core/elasticsearch/core-elasticsearch-server/src/contracts.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index 7a4d8c90d652d..d2b14025c8efa 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server'] --- import kbnCoreElasticsearchServerObj from './kbn_core_elasticsearch_server.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 116 | 0 | 56 | 0 | +| 117 | 0 | 56 | 0 | ## Server diff --git a/api_docs/kbn_core_elasticsearch_server_internal.devdocs.json b/api_docs/kbn_core_elasticsearch_server_internal.devdocs.json index 89c6626b9fd7d..a0e2b420b19bc 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.devdocs.json +++ b/api_docs/kbn_core_elasticsearch_server_internal.devdocs.json @@ -3170,7 +3170,7 @@ "label": "ElasticsearchConfigType", "description": [], "signature": [ - "{ readonly username?: string | undefined; readonly password?: string | undefined; readonly serviceAccountToken?: string | undefined; readonly ssl: Readonly<{ key?: string | undefined; certificateAuthorities?: string | string[] | undefined; certificate?: string | undefined; keyPassphrase?: string | undefined; } & { verificationMode: \"none\" | \"full\" | \"certificate\"; keystore: Readonly<{ password?: string | undefined; path?: string | undefined; } & {}>; truststore: Readonly<{ password?: string | undefined; path?: string | undefined; } & {}>; alwaysPresentCertificate: boolean; }>; readonly healthCheck: Readonly<{} & { delay: moment.Duration; startupDelay: moment.Duration; }>; readonly hosts: string | string[]; readonly apiVersion: string; readonly customHeaders: Record; readonly sniffOnStart: boolean; readonly sniffInterval: false | moment.Duration; readonly sniffOnConnectionFault: boolean; readonly maxSockets: number; readonly maxIdleSockets: number; readonly maxResponseSize: false | ", + "{ readonly username?: string | undefined; readonly password?: string | undefined; readonly serviceAccountToken?: string | undefined; readonly publicBaseUrl?: string | undefined; readonly ssl: Readonly<{ key?: string | undefined; certificateAuthorities?: string | string[] | undefined; certificate?: string | undefined; keyPassphrase?: string | undefined; } & { verificationMode: \"none\" | \"full\" | \"certificate\"; keystore: Readonly<{ password?: string | undefined; path?: string | undefined; } & {}>; truststore: Readonly<{ password?: string | undefined; path?: string | undefined; } & {}>; alwaysPresentCertificate: boolean; }>; readonly healthCheck: Readonly<{} & { delay: moment.Duration; startupDelay: moment.Duration; }>; readonly hosts: string | string[]; readonly apiVersion: string; readonly customHeaders: Record; readonly sniffOnStart: boolean; readonly sniffInterval: false | moment.Duration; readonly sniffOnConnectionFault: boolean; readonly maxSockets: number; readonly maxIdleSockets: number; readonly maxResponseSize: false | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -3524,7 +3524,15 @@ "section": "def-common.Type", "text": "Type" }, - "; }>" + "; publicBaseUrl: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; }>" ], "path": "packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_config.ts", "deprecated": false, diff --git a/api_docs/kbn_core_elasticsearch_server_internal.mdx b/api_docs/kbn_core_elasticsearch_server_internal.mdx index b862638404f10..1a3e36cb85b5a 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-09-04 +date: 2024-09-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.devdocs.json b/api_docs/kbn_core_elasticsearch_server_mocks.devdocs.json index 903e2f228cd97..702a8890af3d9 100644 --- a/api_docs/kbn_core_elasticsearch_server_mocks.devdocs.json +++ b/api_docs/kbn_core_elasticsearch_server_mocks.devdocs.json @@ -22,7 +22,7 @@ "label": "MockedElasticSearchServiceSetup", "description": [], "signature": [ - "{ setUnauthorizedErrorHandler: jest.MockInstance Promise<{ histogramBarTarget: number; }>) | undefined" + ], + "path": "packages/kbn-esql-validation-autocomplete/src/shared/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] } ], "initialIsOpen": false diff --git a/api_docs/kbn_esql_validation_autocomplete.mdx b/api_docs/kbn_esql_validation_autocomplete.mdx index 8f24b4f68ab85..3c2bac2dc54a0 100644 --- a/api_docs/kbn_esql_validation_autocomplete.mdx +++ b/api_docs/kbn_esql_validation_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-validation-autocomplete title: "@kbn/esql-validation-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-validation-autocomplete plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-validation-autocomplete'] --- import kbnEsqlValidationAutocompleteObj from './kbn_esql_validation_autocomplete.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 196 | 0 | 184 | 10 | +| 197 | 0 | 185 | 10 | ## Common diff --git a/api_docs/kbn_event_annotation_common.mdx b/api_docs/kbn_event_annotation_common.mdx index 4068354e9f72d..693b6956a3d4c 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-09-04 +date: 2024-09-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 f16d5e6f2d8cd..d0ec4e7ebbf85 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-09-04 +date: 2024-09-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 3a3e454bedd2d..7c5c00a71ae50 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-09-04 +date: 2024-09-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 e7f07db91fd62..1dff38ce61c5b 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-09-04 +date: 2024-09-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 34b34b59b24c7..c432b29fd1c1d 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-09-04 +date: 2024-09-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 94b18d555a77c..2644964058071 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-09-04 +date: 2024-09-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_formatters.mdx b/api_docs/kbn_formatters.mdx index c18d2d4feaa6f..1302f882b044c 100644 --- a/api_docs/kbn_formatters.mdx +++ b/api_docs/kbn_formatters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-formatters title: "@kbn/formatters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/formatters plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/formatters'] --- import kbnFormattersObj from './kbn_formatters.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_services.mdx b/api_docs/kbn_ftr_common_functional_services.mdx index 8fb6ebf0bafe3..c6a9149830d6e 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-09-04 +date: 2024-09-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.mdx b/api_docs/kbn_ftr_common_functional_ui_services.mdx index 35036ad4307fa..5061d2a7cd440 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-ui-services'] --- import kbnFtrCommonFunctionalUiServicesObj from './kbn_ftr_common_functional_ui_services.devdocs.json'; diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index d3f681d908b88..b2d6e8faa8056 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-09-04 +date: 2024-09-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 ab8dca013e975..241dbcc39e53b 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-09-04 +date: 2024-09-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 290aeb7e3ad3d..9f5bf9f5d5522 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_grid_layout.mdx b/api_docs/kbn_grid_layout.mdx index 8822819530a3a..a2dd470ec8a2a 100644 --- a/api_docs/kbn_grid_layout.mdx +++ b/api_docs/kbn_grid_layout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-grid-layout title: "@kbn/grid-layout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/grid-layout plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/grid-layout'] --- import kbnGridLayoutObj from './kbn_grid_layout.devdocs.json'; diff --git a/api_docs/kbn_grouping.mdx b/api_docs/kbn_grouping.mdx index 7abc8239f7a17..1792959ecf851 100644 --- a/api_docs/kbn_grouping.mdx +++ b/api_docs/kbn_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-grouping title: "@kbn/grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/grouping plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/grouping'] --- import kbnGroupingObj from './kbn_grouping.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index 511488182bd6e..ca0718bd540f4 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-09-04 +date: 2024-09-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 a4208754d01e7..b6bb256b9cddf 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-09-04 +date: 2024-09-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 b13bc8e541396..34cc9178cbcb3 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-09-04 +date: 2024-09-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 9d60b2b4fc2f5..8d85a8c281180 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-09-04 +date: 2024-09-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 c46dc8292555c..9b64534bd2666 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-09-04 +date: 2024-09-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 a1d8721da3e26..cd5a355fb6319 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-09-04 +date: 2024-09-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 f11b214e4c1b1..353b96613bd88 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-09-04 +date: 2024-09-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 410a04682e121..f977064f37937 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-09-04 +date: 2024-09-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 a1b0513581707..d2fbf877c1577 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_index_management.mdx b/api_docs/kbn_index_management.mdx index d67e8e0ea414a..607486ca0e208 100644 --- a/api_docs/kbn_index_management.mdx +++ b/api_docs/kbn_index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-index-management title: "@kbn/index-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/index-management plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/index-management'] --- import kbnIndexManagementObj from './kbn_index_management.devdocs.json'; diff --git a/api_docs/kbn_inference_integration_flyout.mdx b/api_docs/kbn_inference_integration_flyout.mdx index d6ea4cdd3955b..8f24cafac37e6 100644 --- a/api_docs/kbn_inference_integration_flyout.mdx +++ b/api_docs/kbn_inference_integration_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-inference_integration_flyout title: "@kbn/inference_integration_flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/inference_integration_flyout plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/inference_integration_flyout'] --- import kbnInferenceIntegrationFlyoutObj from './kbn_inference_integration_flyout.devdocs.json'; diff --git a/api_docs/kbn_infra_forge.mdx b/api_docs/kbn_infra_forge.mdx index 0b21369d169e3..fe04b9439c425 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-09-04 +date: 2024-09-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 22fb6aeeb0b42..736e0f0acc87e 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_investigation_shared.mdx b/api_docs/kbn_investigation_shared.mdx index 64c4e845ebaba..c3c51b0fc45e1 100644 --- a/api_docs/kbn_investigation_shared.mdx +++ b/api_docs/kbn_investigation_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-investigation-shared title: "@kbn/investigation-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/investigation-shared plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/investigation-shared'] --- import kbnInvestigationSharedObj from './kbn_investigation_shared.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index 8d3fb0b07414a..f7b7ee5878d38 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-09-04 +date: 2024-09-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_ipynb.mdx b/api_docs/kbn_ipynb.mdx index 1073439b7c70a..32ed1dc00ebdc 100644 --- a/api_docs/kbn_ipynb.mdx +++ b/api_docs/kbn_ipynb.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ipynb title: "@kbn/ipynb" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ipynb plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ipynb'] --- import kbnIpynbObj from './kbn_ipynb.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index 941b4dd524151..7045ce79cf935 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-09-04 +date: 2024-09-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 6fca2bfb13625..d33da1b416c56 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-09-04 +date: 2024-09-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 c60b50a4c1612..ad065e6f82b0e 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-ast'] --- import kbnJsonAstObj from './kbn_json_ast.devdocs.json'; diff --git a/api_docs/kbn_json_schemas.mdx b/api_docs/kbn_json_schemas.mdx index 2b5894f5902f8..fef71d5ac45ce 100644 --- a/api_docs/kbn_json_schemas.mdx +++ b/api_docs/kbn_json_schemas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-schemas title: "@kbn/json-schemas" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-schemas plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-schemas'] --- import kbnJsonSchemasObj from './kbn_json_schemas.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 90b88bf507a41..01290ba58c883 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-09-04 +date: 2024-09-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 decddf8c1c6dc..e09316997218a 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-09-04 +date: 2024-09-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 49ad601e68d1d..ba5df45ec8009 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-09-04 +date: 2024-09-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 39f17c7d5e4c8..e465902b0809c 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-09-04 +date: 2024-09-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 c821a5a7ba606..9b8c73fee565f 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-09-04 +date: 2024-09-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 3b93e22461bec..d6c195a08184e 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] --- import kbnLoggingMocksObj from './kbn_logging_mocks.devdocs.json'; diff --git a/api_docs/kbn_managed_content_badge.mdx b/api_docs/kbn_managed_content_badge.mdx index 87b9fb9dbff04..95437027ffcfa 100644 --- a/api_docs/kbn_managed_content_badge.mdx +++ b/api_docs/kbn_managed_content_badge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-content-badge title: "@kbn/managed-content-badge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-content-badge plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-content-badge'] --- import kbnManagedContentBadgeObj from './kbn_managed_content_badge.devdocs.json'; diff --git a/api_docs/kbn_managed_vscode_config.mdx b/api_docs/kbn_managed_vscode_config.mdx index 7899d63814ee8..c64ac1ed05f61 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-09-04 +date: 2024-09-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 f827979a70045..38216ccb60d36 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-09-04 +date: 2024-09-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 0b5c093b0d9af..56dc420cdacf3 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-09-04 +date: 2024-09-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 72d2ecd893be6..17879f353b82b 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-09-04 +date: 2024-09-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 dda8e3d9e7b62..41276872b16a4 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-09-04 +date: 2024-09-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 7cb0210543e57..7816036b6d997 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-09-04 +date: 2024-09-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 f2863f3f45080..5e33498671a85 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-09-04 +date: 2024-09-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 ebfd96fd4b010..0b7b89a26c730 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-09-04 +date: 2024-09-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 83b24df9b40e5..a8cca5758acd1 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-09-04 +date: 2024-09-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 6cf89e770e159..10f725e73d23d 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-09-04 +date: 2024-09-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 c57ba88e6e8d0..56c9b663b3715 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-09-04 +date: 2024-09-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 60ac8e4ad5f66..3ef1a7860d24c 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-09-04 +date: 2024-09-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 2928501aebd14..b3f9e5f8b7dfc 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-09-04 +date: 2024-09-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 3432f3f90fa4b..943a315f43c0c 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-09-04 +date: 2024-09-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 7f2904002c499..ffb986796cad8 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-09-04 +date: 2024-09-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 47f28165bdf8a..223f657e44896 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-09-04 +date: 2024-09-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 2138126b24272..1a63c3f3dc070 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-09-04 +date: 2024-09-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_cancellable_search.mdx b/api_docs/kbn_ml_cancellable_search.mdx index b548bc944060e..2d7633a64bdc4 100644 --- a/api_docs/kbn_ml_cancellable_search.mdx +++ b/api_docs/kbn_ml_cancellable_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-cancellable-search title: "@kbn/ml-cancellable-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-cancellable-search plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-cancellable-search'] --- import kbnMlCancellableSearchObj from './kbn_ml_cancellable_search.devdocs.json'; diff --git a/api_docs/kbn_ml_category_validator.mdx b/api_docs/kbn_ml_category_validator.mdx index c40aace563729..0af4da26f7cb4 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-09-04 +date: 2024-09-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 73de4ec119c6b..61e7f34f4dd18 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-09-04 +date: 2024-09-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 3fa5f7d9c946e..c1bd18574756b 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-09-04 +date: 2024-09-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 156d4b84d8e7f..0b2a256e899d7 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-09-04 +date: 2024-09-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 6da632ed5eeeb..9e8508ea1f61a 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-09-04 +date: 2024-09-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 652c238f4973b..22c022b158d29 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-09-04 +date: 2024-09-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 cd96d5a38eeff..1561eff2cf39c 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-09-04 +date: 2024-09-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 f0516390e768a..80fa5d7cae138 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-09-04 +date: 2024-09-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 a04530433bbe2..54df1f4bc2ff0 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-09-04 +date: 2024-09-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 bc73de9254e3f..5780c410537c3 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-09-04 +date: 2024-09-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 cc40794f097f2..3d441b0d33ae3 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-09-04 +date: 2024-09-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 10511a9a17efc..e9545a2edee98 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-09-04 +date: 2024-09-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 af3846a090d7b..bb4f984262829 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-09-04 +date: 2024-09-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 030702d4f680d..bf9191ad0f631 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-09-04 +date: 2024-09-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 d4c5a9c24fe5a..56169650d4938 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-09-04 +date: 2024-09-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 d22ac5d767184..b4ba29a718ce3 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-09-04 +date: 2024-09-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 6d22b27ddc9c4..8a127c154e509 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-09-04 +date: 2024-09-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 70917fd530a12..93f06b90e89c5 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-09-04 +date: 2024-09-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 7fcef8bc31430..51ff752d341d4 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-09-04 +date: 2024-09-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_time_buckets.mdx b/api_docs/kbn_ml_time_buckets.mdx index f69e7b152d8c3..3aed26f34ae63 100644 --- a/api_docs/kbn_ml_time_buckets.mdx +++ b/api_docs/kbn_ml_time_buckets.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-time-buckets title: "@kbn/ml-time-buckets" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-time-buckets plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-time-buckets'] --- import kbnMlTimeBucketsObj from './kbn_ml_time_buckets.devdocs.json'; diff --git a/api_docs/kbn_ml_trained_models_utils.mdx b/api_docs/kbn_ml_trained_models_utils.mdx index d592a178610b9..521779b15573a 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-09-04 +date: 2024-09-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 9f484e34d2757..04dc8d051cf99 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-09-04 +date: 2024-09-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 76796298613d7..0eeea25294d0f 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-09-04 +date: 2024-09-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_mock_idp_utils.mdx b/api_docs/kbn_mock_idp_utils.mdx index d67cd116c2959..ee671096e6025 100644 --- a/api_docs/kbn_mock_idp_utils.mdx +++ b/api_docs/kbn_mock_idp_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mock-idp-utils title: "@kbn/mock-idp-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mock-idp-utils plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mock-idp-utils'] --- import kbnMockIdpUtilsObj from './kbn_mock_idp_utils.devdocs.json'; diff --git a/api_docs/kbn_monaco.devdocs.json b/api_docs/kbn_monaco.devdocs.json index 6034d3f573795..50ee211f14029 100644 --- a/api_docs/kbn_monaco.devdocs.json +++ b/api_docs/kbn_monaco.devdocs.json @@ -523,6 +523,22 @@ "path": "packages/kbn-esql-validation-autocomplete/src/shared/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/monaco", + "id": "def-common.ESQLCallbacks.getPreferences", + "type": "Function", + "tags": [], + "label": "getPreferences", + "description": [], + "signature": [ + "(() => Promise<{ histogramBarTarget: number; }>) | undefined" + ], + "path": "packages/kbn-esql-validation-autocomplete/src/shared/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] } ], "initialIsOpen": false diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index cc54250116e74..85ab35a10ee7b 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 120 | 0 | 120 | 3 | +| 121 | 0 | 121 | 3 | ## Common diff --git a/api_docs/kbn_object_versioning.mdx b/api_docs/kbn_object_versioning.mdx index 56ec5ba8cefed..ae3f016c15d5f 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/object-versioning'] --- import kbnObjectVersioningObj from './kbn_object_versioning.devdocs.json'; diff --git a/api_docs/kbn_object_versioning_utils.mdx b/api_docs/kbn_object_versioning_utils.mdx index 4f6bdffbc42c0..56880e15bff3d 100644 --- a/api_docs/kbn_object_versioning_utils.mdx +++ b/api_docs/kbn_object_versioning_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-object-versioning-utils title: "@kbn/object-versioning-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/object-versioning-utils plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/object-versioning-utils'] --- import kbnObjectVersioningUtilsObj from './kbn_object_versioning_utils.devdocs.json'; diff --git a/api_docs/kbn_observability_alert_details.mdx b/api_docs/kbn_observability_alert_details.mdx index 0be7162b4177b..51e5262ce88c0 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-09-04 +date: 2024-09-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_rule_utils.mdx b/api_docs/kbn_observability_alerting_rule_utils.mdx index 54a6b2a1439c1..56ff2c52642b4 100644 --- a/api_docs/kbn_observability_alerting_rule_utils.mdx +++ b/api_docs/kbn_observability_alerting_rule_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alerting-rule-utils title: "@kbn/observability-alerting-rule-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alerting-rule-utils plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alerting-rule-utils'] --- import kbnObservabilityAlertingRuleUtilsObj from './kbn_observability_alerting_rule_utils.devdocs.json'; diff --git a/api_docs/kbn_observability_alerting_test_data.mdx b/api_docs/kbn_observability_alerting_test_data.mdx index c65729ec169be..0865cde4f975a 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-09-04 +date: 2024-09-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 56b3991e4a19d..c42b538078ac5 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-09-04 +date: 2024-09-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 a1b3574287f44..8dfab62d17710 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-09-04 +date: 2024-09-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 20ed1d4ee9e5f..46d4ca0a1b0e4 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-09-04 +date: 2024-09-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 6274a608fe97f..14eba650daad3 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-09-04 +date: 2024-09-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 6ca37eca11166..be9c399b6fd8b 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-09-04 +date: 2024-09-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 2106f842157c4..14f8f9054c744 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-09-04 +date: 2024-09-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 4e49a09095334..bd923556da76c 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-09-04 +date: 2024-09-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 e3774c6034cc4..5743194a29803 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-09-04 +date: 2024-09-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_check.mdx b/api_docs/kbn_plugin_check.mdx index 7dad7d321979c..485aea6888c8a 100644 --- a/api_docs/kbn_plugin_check.mdx +++ b/api_docs/kbn_plugin_check.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-check title: "@kbn/plugin-check" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-check plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-check'] --- import kbnPluginCheckObj from './kbn_plugin_check.devdocs.json'; diff --git a/api_docs/kbn_plugin_generator.mdx b/api_docs/kbn_plugin_generator.mdx index d9c4612407a92..b067c614be8cb 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-09-04 +date: 2024-09-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 6c3432a8e62cb..6b1122f3bc273 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_presentation_containers.mdx b/api_docs/kbn_presentation_containers.mdx index 8cf2c4ae4a739..e761941dd21a9 100644 --- a/api_docs/kbn_presentation_containers.mdx +++ b/api_docs/kbn_presentation_containers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-presentation-containers title: "@kbn/presentation-containers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/presentation-containers plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-containers'] --- import kbnPresentationContainersObj from './kbn_presentation_containers.devdocs.json'; diff --git a/api_docs/kbn_presentation_publishing.mdx b/api_docs/kbn_presentation_publishing.mdx index a98b30e5b8237..07585358e1775 100644 --- a/api_docs/kbn_presentation_publishing.mdx +++ b/api_docs/kbn_presentation_publishing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-presentation-publishing title: "@kbn/presentation-publishing" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/presentation-publishing plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-publishing'] --- import kbnPresentationPublishingObj from './kbn_presentation_publishing.devdocs.json'; diff --git a/api_docs/kbn_profiling_utils.mdx b/api_docs/kbn_profiling_utils.mdx index 889a5bc39ffce..fbe5a35b6a596 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-09-04 +date: 2024-09-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 07f210d027d18..74f493c6ddec8 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-09-04 +date: 2024-09-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 22be016c7065b..72f153531a794 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_react_hooks.mdx b/api_docs/kbn_react_hooks.mdx index 2f3d31c43c10c..b6274ae6f2e4f 100644 --- a/api_docs/kbn_react_hooks.mdx +++ b/api_docs/kbn_react_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-hooks title: "@kbn/react-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-hooks plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-hooks'] --- import kbnReactHooksObj from './kbn_react_hooks.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_common.mdx b/api_docs/kbn_react_kibana_context_common.mdx index 35f9face2066f..ed83af357c5f9 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-09-04 +date: 2024-09-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 33986673f7c9e..407130f15a530 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-09-04 +date: 2024-09-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 85522fbeec5cd..4410907699391 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-09-04 +date: 2024-09-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 522f5540a0a28..4c8275a1f844d 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-09-04 +date: 2024-09-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 701262a1c6202..b5f922f6dc925 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-09-04 +date: 2024-09-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 a1e811c670f38..54e03782cfe23 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-09-04 +date: 2024-09-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_recently_accessed.mdx b/api_docs/kbn_recently_accessed.mdx index 74852cfe97930..981ffe9787144 100644 --- a/api_docs/kbn_recently_accessed.mdx +++ b/api_docs/kbn_recently_accessed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-recently-accessed title: "@kbn/recently-accessed" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/recently-accessed plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/recently-accessed'] --- import kbnRecentlyAccessedObj from './kbn_recently_accessed.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index afce45d0a4e5a..0199bb09aa92a 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-09-04 +date: 2024-09-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 66152c140d050..cad136a4212d9 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-09-04 +date: 2024-09-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 89598c5495039..0dab365b8cbe6 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-09-04 +date: 2024-09-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 7212fe86162d6..f04c07e3703f8 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-09-04 +date: 2024-09-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 5186037899cb0..63fa1216fdc45 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-common'] --- import kbnReportingCommonObj from './kbn_reporting_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_csv_share_panel.mdx b/api_docs/kbn_reporting_csv_share_panel.mdx index 8aab840657761..91a1faefd4a54 100644 --- a/api_docs/kbn_reporting_csv_share_panel.mdx +++ b/api_docs/kbn_reporting_csv_share_panel.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-csv-share-panel title: "@kbn/reporting-csv-share-panel" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-csv-share-panel plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-csv-share-panel'] --- import kbnReportingCsvSharePanelObj from './kbn_reporting_csv_share_panel.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv.mdx b/api_docs/kbn_reporting_export_types_csv.mdx index 4c2c55b5044e6..6460d2a03cc1f 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-09-04 +date: 2024-09-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 1715c1683e2fc..202d6d64fd62b 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-09-04 +date: 2024-09-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 839d7402fa94a..d96ba3315c0b7 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-09-04 +date: 2024-09-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 3d58778f8fb77..2df56591936ac 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-09-04 +date: 2024-09-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 3670be002372b..05d5a12bb28f5 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-09-04 +date: 2024-09-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 d4a5141d826d6..95174ef9a1fdc 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-09-04 +date: 2024-09-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 256565ca78b89..55e28ad868310 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-09-04 +date: 2024-09-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 47114d5c0e1e2..35b8d34c3428a 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-09-04 +date: 2024-09-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 52eecec810e55..ea0dad1847850 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-09-04 +date: 2024-09-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 8d8b98ddee18b..d196b7563ede8 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/resizable-layout'] --- import kbnResizableLayoutObj from './kbn_resizable_layout.devdocs.json'; diff --git a/api_docs/kbn_response_ops_feature_flag_service.mdx b/api_docs/kbn_response_ops_feature_flag_service.mdx index 79253a7fdec43..8213d5cc1fd02 100644 --- a/api_docs/kbn_response_ops_feature_flag_service.mdx +++ b/api_docs/kbn_response_ops_feature_flag_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-response-ops-feature-flag-service title: "@kbn/response-ops-feature-flag-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/response-ops-feature-flag-service plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/response-ops-feature-flag-service'] --- import kbnResponseOpsFeatureFlagServiceObj from './kbn_response_ops_feature_flag_service.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index f1bd8870c9afe..fb4b779f59a6a 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_rollup.mdx b/api_docs/kbn_rollup.mdx index 214ba21b97491..ea1efcef77fa8 100644 --- a/api_docs/kbn_rollup.mdx +++ b/api_docs/kbn_rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rollup title: "@kbn/rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rollup plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rollup'] --- import kbnRollupObj from './kbn_rollup.devdocs.json'; diff --git a/api_docs/kbn_router_to_openapispec.mdx b/api_docs/kbn_router_to_openapispec.mdx index 781db8173e579..6651855e31879 100644 --- a/api_docs/kbn_router_to_openapispec.mdx +++ b/api_docs/kbn_router_to_openapispec.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-router-to-openapispec title: "@kbn/router-to-openapispec" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/router-to-openapispec plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/router-to-openapispec'] --- import kbnRouterToOpenapispecObj from './kbn_router_to_openapispec.devdocs.json'; diff --git a/api_docs/kbn_router_utils.mdx b/api_docs/kbn_router_utils.mdx index 9a5744269a248..7a27c8f1da04f 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-09-04 +date: 2024-09-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 5946ec1e70f47..04a4a48a4099b 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-09-04 +date: 2024-09-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 ca34a897bc561..ba17b5e8921e6 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-09-04 +date: 2024-09-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 f2581007d4041..bcd6804c0b9fb 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-09-04 +date: 2024-09-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_screenshotting_server.mdx b/api_docs/kbn_screenshotting_server.mdx index 05d28d93a2bc4..3cebd22ae896e 100644 --- a/api_docs/kbn_screenshotting_server.mdx +++ b/api_docs/kbn_screenshotting_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-screenshotting-server title: "@kbn/screenshotting-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/screenshotting-server plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/screenshotting-server'] --- import kbnScreenshottingServerObj from './kbn_screenshotting_server.devdocs.json'; diff --git a/api_docs/kbn_search_api_panels.mdx b/api_docs/kbn_search_api_panels.mdx index 5a3a7a0cc093e..e826508ba1b46 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-09-04 +date: 2024-09-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 22ecdee55b18b..125f61c370308 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-09-04 +date: 2024-09-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 8a6a39916b011..c5b160de91916 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-09-04 +date: 2024-09-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 281e5c9ab5b42..206ce184f752e 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-09-04 +date: 2024-09-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 0483060fbb8a8..180105b35e6e4 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-09-04 +date: 2024-09-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_search_types.mdx b/api_docs/kbn_search_types.mdx index 9aca26b5a155d..00892575756c1 100644 --- a/api_docs/kbn_search_types.mdx +++ b/api_docs/kbn_search_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-types title: "@kbn/search-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-types plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-types'] --- import kbnSearchTypesObj from './kbn_search_types.devdocs.json'; diff --git a/api_docs/kbn_security_api_key_management.mdx b/api_docs/kbn_security_api_key_management.mdx index 3ddb746cf6f7c..9c3d2bc316824 100644 --- a/api_docs/kbn_security_api_key_management.mdx +++ b/api_docs/kbn_security_api_key_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-api-key-management title: "@kbn/security-api-key-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-api-key-management plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-api-key-management'] --- import kbnSecurityApiKeyManagementObj from './kbn_security_api_key_management.devdocs.json'; diff --git a/api_docs/kbn_security_authorization_core.mdx b/api_docs/kbn_security_authorization_core.mdx index 0247ed5a45bce..0a5bb2b14499b 100644 --- a/api_docs/kbn_security_authorization_core.mdx +++ b/api_docs/kbn_security_authorization_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-authorization-core title: "@kbn/security-authorization-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-authorization-core plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-authorization-core'] --- import kbnSecurityAuthorizationCoreObj from './kbn_security_authorization_core.devdocs.json'; diff --git a/api_docs/kbn_security_form_components.mdx b/api_docs/kbn_security_form_components.mdx index ada47bf2c1198..f77da6fdeda69 100644 --- a/api_docs/kbn_security_form_components.mdx +++ b/api_docs/kbn_security_form_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-form-components title: "@kbn/security-form-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-form-components plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-form-components'] --- import kbnSecurityFormComponentsObj from './kbn_security_form_components.devdocs.json'; diff --git a/api_docs/kbn_security_hardening.mdx b/api_docs/kbn_security_hardening.mdx index 18fd6c268ac43..30e5fc9f95986 100644 --- a/api_docs/kbn_security_hardening.mdx +++ b/api_docs/kbn_security_hardening.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-hardening title: "@kbn/security-hardening" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-hardening plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-hardening'] --- import kbnSecurityHardeningObj from './kbn_security_hardening.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_common.mdx b/api_docs/kbn_security_plugin_types_common.mdx index ccb7267d86577..a79d591892fdc 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-09-04 +date: 2024-09-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 57c9bd94560f6..a3daebc35f052 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-09-04 +date: 2024-09-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 e6d2a30443b0a..84c4d394d9359 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-09-04 +date: 2024-09-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_role_management_model.mdx b/api_docs/kbn_security_role_management_model.mdx index ab238040178b9..fc819002a000a 100644 --- a/api_docs/kbn_security_role_management_model.mdx +++ b/api_docs/kbn_security_role_management_model.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-role-management-model title: "@kbn/security-role-management-model" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-role-management-model plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-role-management-model'] --- import kbnSecurityRoleManagementModelObj from './kbn_security_role_management_model.devdocs.json'; diff --git a/api_docs/kbn_security_solution_common.mdx b/api_docs/kbn_security_solution_common.mdx index ac8c2b774bc2b..501fcc703e7f6 100644 --- a/api_docs/kbn_security_solution_common.mdx +++ b/api_docs/kbn_security_solution_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-common title: "@kbn/security-solution-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-common plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-common'] --- import kbnSecuritySolutionCommonObj from './kbn_security_solution_common.devdocs.json'; diff --git a/api_docs/kbn_security_solution_distribution_bar.mdx b/api_docs/kbn_security_solution_distribution_bar.mdx index 3af5682c67e64..16068df97ea45 100644 --- a/api_docs/kbn_security_solution_distribution_bar.mdx +++ b/api_docs/kbn_security_solution_distribution_bar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-distribution-bar title: "@kbn/security-solution-distribution-bar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-distribution-bar plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-distribution-bar'] --- import kbnSecuritySolutionDistributionBarObj from './kbn_security_solution_distribution_bar.devdocs.json'; diff --git a/api_docs/kbn_security_solution_features.mdx b/api_docs/kbn_security_solution_features.mdx index 8f294d89c970b..19f3af0cb192a 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-09-04 +date: 2024-09-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 3b9a818ef5ba7..db71cd1bcfdb7 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-09-04 +date: 2024-09-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 f999ee849f789..b3ba237ee78a6 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-09-04 +date: 2024-09-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 ee7c468413ae2..250016039e855 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-09-04 +date: 2024-09-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_security_ui_components.mdx b/api_docs/kbn_security_ui_components.mdx index 943d19da3734d..d1625f6e920cd 100644 --- a/api_docs/kbn_security_ui_components.mdx +++ b/api_docs/kbn_security_ui_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-ui-components title: "@kbn/security-ui-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-ui-components plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-ui-components'] --- import kbnSecurityUiComponentsObj from './kbn_security_ui_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index 73b22d223a38f..7b57e4466c414 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-09-04 +date: 2024-09-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 94a0497829528..6d0578a32bcfd 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-09-04 +date: 2024-09-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 aed6d30854700..089a29aefea06 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-09-04 +date: 2024-09-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 ab617c53cc5a5..9bfce93577d45 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-09-04 +date: 2024-09-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 59c397bad97a2..85548f69d6d27 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-09-04 +date: 2024-09-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_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index e8ea613b18bca..43abdf53cc5f1 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-09-04 +date: 2024-09-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 7f74bbe1b4a3f..731ebacaffa47 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-09-04 +date: 2024-09-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 1a9c8987ae96a..82201967319f1 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-09-04 +date: 2024-09-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 fce0b8aeb01a0..f6ed7d9b759ed 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-09-04 +date: 2024-09-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 c3cffbff1588e..36c07681a1336 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-09-04 +date: 2024-09-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 753e45141c420..21070ad4a3af1 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-09-04 +date: 2024-09-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 4c246a77bccc6..ee2dd11c96351 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-09-04 +date: 2024-09-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 8dd4184bd489f..95e310196a9d4 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-09-04 +date: 2024-09-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 589465a7e60af..a19cf38117484 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-09-04 +date: 2024-09-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 598b8e3181072..015b67b137a0f 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-09-04 +date: 2024-09-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 fea6f723429be..570645bb79985 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-09-04 +date: 2024-09-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 1d468c71c1f3e..a0f958027f7f3 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-09-04 +date: 2024-09-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 e6cdb09bcdcd7..32b9ce2128fee 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-09-04 +date: 2024-09-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 e600e5e227130..686a378cbd168 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-09-04 +date: 2024-09-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_server_route_repository_client.mdx b/api_docs/kbn_server_route_repository_client.mdx index 298d6d199be78..c6c53bbac56ed 100644 --- a/api_docs/kbn_server_route_repository_client.mdx +++ b/api_docs/kbn_server_route_repository_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository-client title: "@kbn/server-route-repository-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository-client plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository-client'] --- import kbnServerRouteRepositoryClientObj from './kbn_server_route_repository_client.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository_utils.mdx b/api_docs/kbn_server_route_repository_utils.mdx index 1707958f08492..b390fdac8869a 100644 --- a/api_docs/kbn_server_route_repository_utils.mdx +++ b/api_docs/kbn_server_route_repository_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository-utils title: "@kbn/server-route-repository-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository-utils plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository-utils'] --- import kbnServerRouteRepositoryUtilsObj from './kbn_server_route_repository_utils.devdocs.json'; diff --git a/api_docs/kbn_serverless_common_settings.mdx b/api_docs/kbn_serverless_common_settings.mdx index 036b329a0404f..80bcbad24334d 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-09-04 +date: 2024-09-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 daf5973ad37e3..a1139038d1ea9 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-09-04 +date: 2024-09-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 86f7ef794a54e..884c921ba20ff 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-09-04 +date: 2024-09-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 360f251a9f6e0..badba1ee031b9 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-09-04 +date: 2024-09-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 db072a8c01231..8d576f95e56f8 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-09-04 +date: 2024-09-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 f25753ab130ac..160174ef0c582 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-09-04 +date: 2024-09-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 336f0455bac07..9e6e246e9f91b 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-09-04 +date: 2024-09-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 c9f95c974e2b4..2f1898161048f 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-09-04 +date: 2024-09-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 6868f49737991..c8cea5f3f9ce9 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-09-04 +date: 2024-09-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 0eb21c5b0aa1c..b83f24a936f3b 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-09-04 +date: 2024-09-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 d56ff27f9f56a..f661389af532d 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-09-04 +date: 2024-09-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 f5ea6cb6a8756..7879a537479df 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-09-04 +date: 2024-09-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 c9e33fb5a6749..150aa5fbcbb08 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-09-04 +date: 2024-09-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 b126750227fe9..c1edd8ee3e0b4 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-09-04 +date: 2024-09-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 8f3e2d3bdbf8e..16ce5ab937322 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-09-04 +date: 2024-09-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 3a7bcc434f3b4..6fec208bb40ba 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-09-04 +date: 2024-09-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 6c1706d3c57b1..68862f3d2a8c9 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-09-04 +date: 2024-09-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 0269fdbbf4bc7..fe20f2aa919a7 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-09-04 +date: 2024-09-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 4f2095783395c..9bb6a34051e88 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-09-04 +date: 2024-09-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 729fc14af688c..18dd1de18c5c9 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-09-04 +date: 2024-09-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 2e24fe9dca0c3..65b9b8203c906 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-09-04 +date: 2024-09-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 46a624f32dc53..ed768e8843a04 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-09-04 +date: 2024-09-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 ac50ff0502bae..b8d85630e975f 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-09-04 +date: 2024-09-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 a2621122b26ad..98d9f8622cfc3 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-09-04 +date: 2024-09-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 1ee2f1621629e..474cc31905553 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-09-04 +date: 2024-09-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 0fbc4d39797ee..d21b436edaef0 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-09-04 +date: 2024-09-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 f2c2820ccf63e..633755bbf2e31 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-09-04 +date: 2024-09-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 a84cf1d9209cf..a322826a76195 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-09-04 +date: 2024-09-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 7e2df7017d582..e97e4a82610f8 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-09-04 +date: 2024-09-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 5834fd12cb166..5c3e50b8daee1 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-09-04 +date: 2024-09-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 f556b25893265..ed709aecf9ba3 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-09-04 +date: 2024-09-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 0034ed2775f04..81fef1390de92 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-09-04 +date: 2024-09-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 d20551adc6ec7..036b423c25978 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-09-04 +date: 2024-09-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 17448fa4d0eea..019ba1f463582 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-09-04 +date: 2024-09-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 095523ea354c7..a44077c5140b4 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-09-04 +date: 2024-09-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 fd82a288a2ebe..8cd73b3a96927 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-09-04 +date: 2024-09-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 3a1cf8509382e..4dfa949a3c92c 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-09-04 +date: 2024-09-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 7608db04c35ef..5260400321f5b 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-09-04 +date: 2024-09-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 bc42e12c5eb5b..adcdac68c1caf 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-09-04 +date: 2024-09-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 841b608a5daa7..03761fc3b9ca7 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-09-04 +date: 2024-09-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 4f9ac10166644..3b80b50b06615 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-09-04 +date: 2024-09-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 290cbc9322a2a..0399531c9034c 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-09-04 +date: 2024-09-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 d68ab0bcc6308..c9f70b410c022 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-09-04 +date: 2024-09-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 61707537e684c..cc899c6a93312 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-09-04 +date: 2024-09-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_tabbed_modal.mdx b/api_docs/kbn_shared_ux_tabbed_modal.mdx index de4b9b19560d9..95fbbd145215d 100644 --- a/api_docs/kbn_shared_ux_tabbed_modal.mdx +++ b/api_docs/kbn_shared_ux_tabbed_modal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-tabbed-modal title: "@kbn/shared-ux-tabbed-modal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-tabbed-modal plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-tabbed-modal'] --- import kbnSharedUxTabbedModalObj from './kbn_shared_ux_tabbed_modal.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_table_persist.mdx b/api_docs/kbn_shared_ux_table_persist.mdx index 5b0a03edac53f..38ae8a4bd09f8 100644 --- a/api_docs/kbn_shared_ux_table_persist.mdx +++ b/api_docs/kbn_shared_ux_table_persist.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-table-persist title: "@kbn/shared-ux-table-persist" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-table-persist plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-table-persist'] --- import kbnSharedUxTablePersistObj from './kbn_shared_ux_table_persist.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index f5b92bc61f044..f7eb26133ba69 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-09-04 +date: 2024-09-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 6d5703c52790b..0a5376aa8ca06 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-09-04 +date: 2024-09-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 83f8b61079cf1..9b4e62c34ed68 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-09-04 +date: 2024-09-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_sort_predicates.mdx b/api_docs/kbn_sort_predicates.mdx index 00f0086ab1540..ccfdedc316076 100644 --- a/api_docs/kbn_sort_predicates.mdx +++ b/api_docs/kbn_sort_predicates.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sort-predicates title: "@kbn/sort-predicates" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sort-predicates plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sort-predicates'] --- import kbnSortPredicatesObj from './kbn_sort_predicates.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index df938c55c590f..fc4322a4e2529 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-09-04 +date: 2024-09-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 aaf8416dacfb0..fd56b66e79b04 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-09-04 +date: 2024-09-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 7d040de9cc191..cd2af76db4ffb 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_synthetics_e2e.mdx b/api_docs/kbn_synthetics_e2e.mdx index 57525a0efa81d..e634dae999489 100644 --- a/api_docs/kbn_synthetics_e2e.mdx +++ b/api_docs/kbn_synthetics_e2e.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-synthetics-e2e title: "@kbn/synthetics-e2e" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/synthetics-e2e plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/synthetics-e2e'] --- import kbnSyntheticsE2eObj from './kbn_synthetics_e2e.devdocs.json'; diff --git a/api_docs/kbn_synthetics_private_location.mdx b/api_docs/kbn_synthetics_private_location.mdx index 10c916f446831..14736d9e5583a 100644 --- a/api_docs/kbn_synthetics_private_location.mdx +++ b/api_docs/kbn_synthetics_private_location.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-synthetics-private-location title: "@kbn/synthetics-private-location" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/synthetics-private-location plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/synthetics-private-location'] --- import kbnSyntheticsPrivateLocationObj from './kbn_synthetics_private_location.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index 978e9b2524433..65377fd62be32 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-09-04 +date: 2024-09-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 8f835b18285d7..204366b3c5d25 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_eui_helpers.mdx b/api_docs/kbn_test_eui_helpers.mdx index 7f00c708d2d69..209fa9df96bec 100644 --- a/api_docs/kbn_test_eui_helpers.mdx +++ b/api_docs/kbn_test_eui_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-eui-helpers title: "@kbn/test-eui-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-eui-helpers plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-eui-helpers'] --- import kbnTestEuiHelpersObj from './kbn_test_eui_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index d364104d8639f..547d496b3da85 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-09-04 +date: 2024-09-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 db99dcde34184..d39d839f5616d 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-09-04 +date: 2024-09-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 2a5a38f3dedf8..f0bad151e7de1 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-09-04 +date: 2024-09-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_timerange.mdx b/api_docs/kbn_timerange.mdx index f17fa71943a73..253c68b01c4da 100644 --- a/api_docs/kbn_timerange.mdx +++ b/api_docs/kbn_timerange.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-timerange title: "@kbn/timerange" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/timerange plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/timerange'] --- import kbnTimerangeObj from './kbn_timerange.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index ec482d6ffc521..e4182be00fa43 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-09-04 +date: 2024-09-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 bb1d900e584c2..64ec880d901c9 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-09-04 +date: 2024-09-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_try_in_console.mdx b/api_docs/kbn_try_in_console.mdx index 73a20839f60ba..7f0592a409cbd 100644 --- a/api_docs/kbn_try_in_console.mdx +++ b/api_docs/kbn_try_in_console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-try-in-console title: "@kbn/try-in-console" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/try-in-console plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/try-in-console'] --- import kbnTryInConsoleObj from './kbn_try_in_console.devdocs.json'; diff --git a/api_docs/kbn_ts_projects.mdx b/api_docs/kbn_ts_projects.mdx index 811f9df289f23..24cdd0af279e3 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-09-04 +date: 2024-09-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 1e7878abc9886..3dbfe29115b44 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-09-04 +date: 2024-09-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 4139b45246462..40258e1c962c3 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-09-04 +date: 2024-09-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 4f845c83a1b6e..e2f1cfa99a5d8 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-09-04 +date: 2024-09-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 961e06aa509e3..35bd13479a314 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-09-04 +date: 2024-09-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 d02d246cbb992..26e185c5503de 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-09-04 +date: 2024-09-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 32bb2d5ef722e..4cc5d908f743a 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-09-04 +date: 2024-09-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 f0ef14e11199d..2162de2a5dadc 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-09-04 +date: 2024-09-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 485cb97701713..29596a0da92d9 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-09-04 +date: 2024-09-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_unsaved_changes_prompt.mdx b/api_docs/kbn_unsaved_changes_prompt.mdx index 2485c4138ddb3..b5d91fa4ff9f0 100644 --- a/api_docs/kbn_unsaved_changes_prompt.mdx +++ b/api_docs/kbn_unsaved_changes_prompt.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-prompt title: "@kbn/unsaved-changes-prompt" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-prompt plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-prompt'] --- import kbnUnsavedChangesPromptObj from './kbn_unsaved_changes_prompt.devdocs.json'; diff --git a/api_docs/kbn_use_tracked_promise.mdx b/api_docs/kbn_use_tracked_promise.mdx index bfd0d42c068f1..3545e1e94fa6b 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-09-04 +date: 2024-09-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 6ab3aff6bf587..4b0504ea5ceff 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-09-04 +date: 2024-09-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 7673ed5324131..cbdaace1a6a81 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-09-04 +date: 2024-09-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 d2d412f5ed754..9a0a91c06adb4 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-09-04 +date: 2024-09-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 02402120c5fbf..9e82adef9ae73 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-09-04 +date: 2024-09-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 a547afddd5720..279bf8c61cfb4 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-09-04 +date: 2024-09-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 aef692ac03fbc..d65381f5651d5 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-09-04 +date: 2024-09-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 9df65573fdd10..a9dc384844979 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-09-04 +date: 2024-09-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 5146945ed1a7e..91d251b330f3d 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-09-04 +date: 2024-09-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.mdx b/api_docs/kbn_zod.mdx index 37a32c8663a0e..0911aede9b97b 100644 --- a/api_docs/kbn_zod.mdx +++ b/api_docs/kbn_zod.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-zod title: "@kbn/zod" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/zod plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/zod'] --- import kbnZodObj from './kbn_zod.devdocs.json'; diff --git a/api_docs/kbn_zod_helpers.mdx b/api_docs/kbn_zod_helpers.mdx index 3a819e02c0c64..8db261f7a2116 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-09-04 +date: 2024-09-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 cf03c2818767d..c1b8e3bd9455d 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-09-04 +date: 2024-09-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 523380eae221a..9250990b38197 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-09-04 +date: 2024-09-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 ce22af8a4af40..16e9ae91f0d74 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-09-04 +date: 2024-09-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 d897e59c0679f..ca9b6e83a13e2 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-09-04 +date: 2024-09-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 babb32abaf909..61522f23610cc 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-09-04 +date: 2024-09-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 eab4906c08acc..38f1ec2520c4a 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-09-04 +date: 2024-09-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 0cc079aefdde0..0236554d3b276 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-09-04 +date: 2024-09-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 7c78dbd8ee683..470bc120b0eac 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-09-04 +date: 2024-09-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 9cbb5461fbab9..71c8a1663c507 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-09-04 +date: 2024-09-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 83370ffe7317f..5e1653a82f8ae 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/logs_data_access.mdx b/api_docs/logs_data_access.mdx index 4eb7815516970..6e94638f6c73c 100644 --- a/api_docs/logs_data_access.mdx +++ b/api_docs/logs_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsDataAccess title: "logsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the logsDataAccess plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsDataAccess'] --- import logsDataAccessObj from './logs_data_access.devdocs.json'; diff --git a/api_docs/logs_explorer.mdx b/api_docs/logs_explorer.mdx index 7d38f1033707f..c49deda7fa6a1 100644 --- a/api_docs/logs_explorer.mdx +++ b/api_docs/logs_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsExplorer title: "logsExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the logsExplorer plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsExplorer'] --- import logsExplorerObj from './logs_explorer.devdocs.json'; diff --git a/api_docs/logs_shared.mdx b/api_docs/logs_shared.mdx index 2494db764b25f..6d645c22994d9 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-09-04 +date: 2024-09-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 8152b3487d704..8dfdc31a8ee22 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-09-04 +date: 2024-09-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 83abb95369e1b..d38516c28eb72 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-09-04 +date: 2024-09-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 b3b00bd073e22..d4ec614b809da 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-09-04 +date: 2024-09-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 de7f986a8678d..7f781cc33e572 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-09-04 +date: 2024-09-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 585cadbe24612..15b093962d3f7 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-09-04 +date: 2024-09-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 a2f6c8fc693fe..3cf1f556c3e2f 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-09-04 +date: 2024-09-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 3d9168c9fcabf..5ffe9c9ef9fbf 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-09-04 +date: 2024-09-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 dbf568f979cbc..b6606e5b4e461 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-09-04 +date: 2024-09-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 b855936d2c0c7..fcd46bcc649c6 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-09-04 +date: 2024-09-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 0a42640104e23..10f271946fddd 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-09-04 +date: 2024-09-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 207351ad4a000..f092976a3570e 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-09-04 +date: 2024-09-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 f7c8e011858e4..684e76c1d4882 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-09-04 +date: 2024-09-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 92649ba2ae59c..ccee1f6ff5aa2 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-09-04 +date: 2024-09-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 93d16c5006beb..818ca6f7d3930 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistant'] --- import observabilityAIAssistantObj from './observability_a_i_assistant.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant_app.mdx b/api_docs/observability_a_i_assistant_app.mdx index 1faad687a496a..e8b7392079da1 100644 --- a/api_docs/observability_a_i_assistant_app.mdx +++ b/api_docs/observability_a_i_assistant_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAIAssistantApp title: "observabilityAIAssistantApp" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAIAssistantApp plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistantApp'] --- import observabilityAIAssistantAppObj from './observability_a_i_assistant_app.devdocs.json'; diff --git a/api_docs/observability_ai_assistant_management.mdx b/api_docs/observability_ai_assistant_management.mdx index 105b2df23e788..a0f1b8ad82df9 100644 --- a/api_docs/observability_ai_assistant_management.mdx +++ b/api_docs/observability_ai_assistant_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAiAssistantManagement title: "observabilityAiAssistantManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAiAssistantManagement plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAiAssistantManagement'] --- import observabilityAiAssistantManagementObj from './observability_ai_assistant_management.devdocs.json'; diff --git a/api_docs/observability_logs_explorer.mdx b/api_docs/observability_logs_explorer.mdx index 007c24e992d09..b0503effd1417 100644 --- a/api_docs/observability_logs_explorer.mdx +++ b/api_docs/observability_logs_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityLogsExplorer title: "observabilityLogsExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityLogsExplorer plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityLogsExplorer'] --- import observabilityLogsExplorerObj from './observability_logs_explorer.devdocs.json'; diff --git a/api_docs/observability_onboarding.mdx b/api_docs/observability_onboarding.mdx index 178d61ff04054..35b77daac7009 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-09-04 +date: 2024-09-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 e57798321e277..0703df8d0a08a 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-09-04 +date: 2024-09-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 f3afcde08300f..862a3e68d55f7 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-09-04 +date: 2024-09-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 f6eb8cf0d76ac..01bf832632aef 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-09-04 +date: 2024-09-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 2d06b51b485a7..d0d5e47c7bcec 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -21,7 +21,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 52901 | 243 | 39737 | 1942 | +| 52942 | 243 | 39777 | 1945 | ## Plugin Directory @@ -49,7 +49,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | The cloud security posture plugin | 14 | 0 | 2 | 2 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 39 | 0 | 30 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Content management app | 149 | 0 | 125 | 6 | -| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Controls Plugin contains embeddable components intended to create a simple query interface for end users, and a powerful editing suite that allows dashboard authors to build controls | 390 | 0 | 381 | 28 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Controls Plugin contains embeddable components intended to create a simple query interface for end users, and a powerful editing suite that allows dashboard authors to build controls | 394 | 0 | 385 | 28 | | crossClusterReplication | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 0 | 0 | 0 | 0 | | customBranding | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Enables customization of Kibana | 0 | 0 | 0 | 0 | | | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | Add custom data integrations so they can be displayed in the Fleet integrations app | 271 | 0 | 252 | 1 | @@ -114,7 +114,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Image embeddable | 1 | 0 | 1 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 4 | 0 | 4 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 238 | 0 | 233 | 1 | -| | [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai-infra) | - | 16 | 0 | 14 | 11 | +| | [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai-infra) | - | 41 | 0 | 39 | 13 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin visualizes data from Filebeat and Metricbeat, and integrates with other Observability solutions | 38 | 0 | 35 | 6 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 4 | 0 | 4 | 0 | | inputControlVis | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Input Control visualization to Kibana | 0 | 0 | 0 | 0 | @@ -256,8 +256,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 1 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 18 | 0 | 18 | 0 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 4 | 0 | 4 | 0 | -| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 56 | 0 | 56 | 9 | -| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 205 | 0 | 205 | 33 | +| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 59 | 0 | 59 | 10 | +| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 208 | 0 | 208 | 33 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 316 | 0 | 315 | 0 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 11 | 0 | 11 | 0 | | | [@elastic/security-defend-workflows](https://github.com/orgs/elastic/teams/security-defend-workflows) | - | 3 | 0 | 3 | 0 | @@ -275,7 +275,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 62 | 0 | 17 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 2 | 0 | | | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 22 | 0 | 22 | 0 | -| | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 49 | 0 | 49 | 0 | +| | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 52 | 0 | 52 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 41 | 0 | 17 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | | | [@elastic/appex-qa](https://github.com/orgs/elastic/teams/appex-qa) | - | 8 | 0 | 4 | 0 | @@ -338,7 +338,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 4 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 22 | 0 | 13 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 38 | 1 | 34 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 116 | 0 | 56 | 0 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 117 | 0 | 56 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 43 | 0 | 38 | 3 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 13 | 1 | 13 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 4 | 1 | @@ -511,7 +511,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 1 | 0 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 152 | 1 | 120 | 15 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 68 | 0 | 64 | 0 | -| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 196 | 0 | 184 | 10 | +| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 197 | 0 | 185 | 10 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 40 | 0 | 40 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 52 | 0 | 52 | 1 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 42 | 0 | 17 | 2 | @@ -595,7 +595,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 18 | 0 | 18 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 42 | 1 | 35 | 1 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 22 | 0 | 16 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 120 | 0 | 120 | 3 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 121 | 0 | 121 | 3 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 55 | 1 | 50 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 10 | 0 | 10 | 2 | diff --git a/api_docs/presentation_panel.mdx b/api_docs/presentation_panel.mdx index a6a272a4847b3..98a45d13d447e 100644 --- a/api_docs/presentation_panel.mdx +++ b/api_docs/presentation_panel.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationPanel title: "presentationPanel" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationPanel plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationPanel'] --- import presentationPanelObj from './presentation_panel.devdocs.json'; diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index 4d5eb2427cc3e..5dc85d2e17c80 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-09-04 +date: 2024-09-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 4f43ea42b1261..526e0d34b5796 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-09-04 +date: 2024-09-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 1afb2f3d0fe85..e61422ed31670 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-09-04 +date: 2024-09-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 b39d2202e4132..4aded26680b42 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-09-04 +date: 2024-09-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 d94cb4f6beab5..fcababb0a5664 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-09-04 +date: 2024-09-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 92589ef0b0bde..acc3dc2594f36 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-09-04 +date: 2024-09-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 4436e21f57fbe..2017213b66911 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-09-04 +date: 2024-09-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 d4b233dcfea35..5d86bff85337e 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-09-04 +date: 2024-09-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 00f947f89fa69..d8bee3f6841d2 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-09-04 +date: 2024-09-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 d0708ca0b3829..9b6a0966c9c3a 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-09-04 +date: 2024-09-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 6c1b890dfa2e4..c31d8330e9525 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-09-04 +date: 2024-09-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 098fa86ed12fc..1cff5ca7e19dd 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-09-04 +date: 2024-09-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 d2165d9903e0c..931642c034eea 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-09-04 +date: 2024-09-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 56a01cb9a488f..f69efb18ff8f5 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-09-04 +date: 2024-09-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 ebb6b4579b66c..e954f30b41c06 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-09-04 +date: 2024-09-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 5a59c6e1a7cd0..5f0ba92ca1c2e 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/search_assistant.mdx b/api_docs/search_assistant.mdx index 464894cd90e6b..b7f82fcdcd9c0 100644 --- a/api_docs/search_assistant.mdx +++ b/api_docs/search_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchAssistant title: "searchAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the searchAssistant plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchAssistant'] --- import searchAssistantObj from './search_assistant.devdocs.json'; diff --git a/api_docs/search_connectors.mdx b/api_docs/search_connectors.mdx index 6561852261e8f..2e5f0e0853f6e 100644 --- a/api_docs/search_connectors.mdx +++ b/api_docs/search_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchConnectors title: "searchConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the searchConnectors plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchConnectors'] --- import searchConnectorsObj from './search_connectors.devdocs.json'; diff --git a/api_docs/search_homepage.mdx b/api_docs/search_homepage.mdx index 85b957fc32a7b..0fc8159df88cf 100644 --- a/api_docs/search_homepage.mdx +++ b/api_docs/search_homepage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchHomepage title: "searchHomepage" image: https://source.unsplash.com/400x175/?github description: API docs for the searchHomepage plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchHomepage'] --- import searchHomepageObj from './search_homepage.devdocs.json'; diff --git a/api_docs/search_indices.mdx b/api_docs/search_indices.mdx index 249f293142ede..19baa807ed5b4 100644 --- a/api_docs/search_indices.mdx +++ b/api_docs/search_indices.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchIndices title: "searchIndices" image: https://source.unsplash.com/400x175/?github description: API docs for the searchIndices plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchIndices'] --- import searchIndicesObj from './search_indices.devdocs.json'; diff --git a/api_docs/search_inference_endpoints.mdx b/api_docs/search_inference_endpoints.mdx index a447457c453ce..897aa79e2921e 100644 --- a/api_docs/search_inference_endpoints.mdx +++ b/api_docs/search_inference_endpoints.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchInferenceEndpoints title: "searchInferenceEndpoints" image: https://source.unsplash.com/400x175/?github description: API docs for the searchInferenceEndpoints plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchInferenceEndpoints'] --- import searchInferenceEndpointsObj from './search_inference_endpoints.devdocs.json'; diff --git a/api_docs/search_notebooks.mdx b/api_docs/search_notebooks.mdx index c7066dbfcdd68..ebfc133b1e565 100644 --- a/api_docs/search_notebooks.mdx +++ b/api_docs/search_notebooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchNotebooks title: "searchNotebooks" image: https://source.unsplash.com/400x175/?github description: API docs for the searchNotebooks plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchNotebooks'] --- import searchNotebooksObj from './search_notebooks.devdocs.json'; diff --git a/api_docs/search_playground.mdx b/api_docs/search_playground.mdx index 8dee517a44d0e..e3b529e4e5d0e 100644 --- a/api_docs/search_playground.mdx +++ b/api_docs/search_playground.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchPlayground title: "searchPlayground" image: https://source.unsplash.com/400x175/?github description: API docs for the searchPlayground plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchPlayground'] --- import searchPlaygroundObj from './search_playground.devdocs.json'; diff --git a/api_docs/security.mdx b/api_docs/security.mdx index ff4d754d44a9b..b853963199089 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index 908cf07283a19..18094d18ce1cf 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-09-04 +date: 2024-09-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 28da3e74463c9..8d0c9f7546518 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-09-04 +date: 2024-09-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 ab922a6ca531b..caeaf76f9ece1 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-09-04 +date: 2024-09-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 63e9d4fe896af..7aac0e7cbc34c 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-09-04 +date: 2024-09-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 168c333e3552f..bdbe6ece4486b 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-09-04 +date: 2024-09-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 9b13e3f4db0eb..dec90a50757cc 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-09-04 +date: 2024-09-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 f966d1969ea3f..6d3dd5a1e6eef 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-09-04 +date: 2024-09-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 ab976b5225130..d849bf9451e12 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/slo.mdx b/api_docs/slo.mdx index a1d7d4f35fbe8..db4b4945cd9d9 100644 --- a/api_docs/slo.mdx +++ b/api_docs/slo.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/slo title: "slo" image: https://source.unsplash.com/400x175/?github description: API docs for the slo plugin -date: 2024-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'slo'] --- import sloObj from './slo.devdocs.json'; diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index 1b205e53302dc..84f839f49e449 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-09-04 +date: 2024-09-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 c7df8aaa01198..6b02645ba1117 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-09-04 +date: 2024-09-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 455b6b8ed44e4..ae9b91785e186 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-09-04 +date: 2024-09-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 dcb5d1128ba36..7fb970b0adb6b 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-09-04 +date: 2024-09-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 d799d6afc7b09..db0dad63c02ae 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-09-04 +date: 2024-09-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 f9856709b2fe4..257594e5044c2 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-09-04 +date: 2024-09-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 c42345ce4e54b..e868719e13a1b 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-09-04 +date: 2024-09-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 8e47c67645ba3..bd81059d9e405 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-09-04 +date: 2024-09-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 ddd60224da44b..b9e9fc35129a7 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index c6a7bcea4b600..3cbc5ac9b928d 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-09-04 +date: 2024-09-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 32c8a1a60df3d..aadf6ba132646 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-09-04 +date: 2024-09-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 c6b403fe1bcb3..6051be7ca4945 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-09-04 +date: 2024-09-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 b024e1f8bee70..e9fc355edc585 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-09-04 +date: 2024-09-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 5baf948dca658..0c4fbd411bcf1 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-09-04 +date: 2024-09-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 9438a6bbdec7f..e7e0c2c0da13f 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-09-04 +date: 2024-09-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 f993534b0c636..6aacc15941021 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-09-04 +date: 2024-09-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 261df406e0d86..d1caaaf392b9e 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-09-04 +date: 2024-09-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 644389a0f6635..197631923c0af 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-09-04 +date: 2024-09-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 93d734215769b..4dec4c04e4178 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-09-04 +date: 2024-09-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 d06d9758541ab..3537a3c580dd6 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-09-04 +date: 2024-09-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 38d05c84acf76..73a13490499fd 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-09-04 +date: 2024-09-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 3d95915bc7d82..c81e5b8ce3d4d 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-09-04 +date: 2024-09-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 eeeb2657d3411..2d887c3c9c36b 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-09-04 +date: 2024-09-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 d53400f12e4fe..b7a5c85a51646 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-09-04 +date: 2024-09-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 d1d5c6798ccf9..765771356e477 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-09-04 +date: 2024-09-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 8c7f820073b1e..2005c03b8e3b2 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-09-04 +date: 2024-09-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 1b7ad85928ea0..64fbda65b2d79 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-09-04 +date: 2024-09-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 0c9930f81bcf2..cc1237157ceae 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-09-04 +date: 2024-09-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 caf3df6733519..efa98f36631d3 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-09-04 +date: 2024-09-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 48c0038915e5f..6fe62590a8cc0 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-09-04 +date: 2024-09-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 fca93f8baecd3..3ee1bb1874a92 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-09-04 +date: 2024-09-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 47c8a6d390614..2c67a4f2e9e4b 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-09-04 +date: 2024-09-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 8abf2b174ba18..c6db455a693c6 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-09-04 +date: 2024-09-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 88482cc64e4b5..d708c57f35bed 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-09-04 +date: 2024-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; From 58352caf758bde6d1ee47eee4b0977ccc14c4806 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 5 Sep 2024 17:30:29 +1000 Subject: [PATCH 13/99] skip failing test suite (#192128) --- x-pack/plugins/osquery/cypress/e2e/all/ecs_mappings.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/osquery/cypress/e2e/all/ecs_mappings.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/ecs_mappings.cy.ts index 5330b7869e6f4..89881c47083fd 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/ecs_mappings.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/ecs_mappings.cy.ts @@ -18,7 +18,8 @@ import { typeInOsqueryFieldInput, } from '../../tasks/live_query'; -describe('EcsMapping', { tags: ['@ess', '@serverless'] }, () => { +// Failing: See https://github.com/elastic/kibana/issues/192128 +describe.skip('EcsMapping', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { initializeDataViews(); }); From c0f4601d4fb077027aff678ad8af56ecbafa7938 Mon Sep 17 00:00:00 2001 From: Bena Kansara <69037875+benakansara@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:53:10 +0200 Subject: [PATCH 14/99] [RCA] Add rule condition charts by default to an investigation started from custom threshold alert (#191858) Resolves https://github.com/elastic/kibana/issues/190513 https://github.com/user-attachments/assets/11d5afa7-ed80-443d-807d-32f4ea241331 --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../items/lens_item/register_lens_item.tsx | 259 ++++++++++++++++++ .../public/items/register_items.ts | 2 + .../investigate_app/tsconfig.json | 2 + .../components/header_actions.tsx | 35 +++ .../hooks/use_add_investigation_item.ts | 47 ++++ .../public/utils/investigation_item_helper.ts | 73 +++++ 6 files changed, 418 insertions(+) create mode 100644 x-pack/plugins/observability_solution/investigate_app/public/items/lens_item/register_lens_item.tsx create mode 100644 x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_add_investigation_item.ts create mode 100644 x-pack/plugins/observability_solution/observability/public/utils/investigation_item_helper.ts diff --git a/x-pack/plugins/observability_solution/investigate_app/public/items/lens_item/register_lens_item.tsx b/x-pack/plugins/observability_solution/investigate_app/public/items/lens_item/register_lens_item.tsx new file mode 100644 index 0000000000000..c81ebec9c6ade --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/public/items/lens_item/register_lens_item.tsx @@ -0,0 +1,259 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { EuiEmptyPrompt } from '@elastic/eui'; +import type { DataView } from '@kbn/data-views-plugin/common'; +import { i18n } from '@kbn/i18n'; +import { type GlobalWidgetParameters } from '@kbn/investigate-plugin/public'; +import React, { useEffect, useState } from 'react'; +import useAsync from 'react-use/lib/useAsync'; + +import { + LensAttributes, + XYLayerOptions, + XYDataLayer, + XYReferenceLinesLayer, + XYByValueAnnotationsLayer, + LensAttributesBuilder, + XYChart, +} from '@kbn/lens-embeddable-utils'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { SerializedSearchSourceFields } from '@kbn/data-plugin/common'; +import { Query, Filter } from '@kbn/es-query'; +import type { Options } from '../register_items'; +import { useKibana } from '../../hooks/use_kibana'; + +interface GenericSearchSourceFields extends SerializedSearchSourceFields { + query?: Query; + filter?: Array>; +} + +interface Props { + timeRange: { + from: string; + to: string; + }; + searchConfiguration: GenericSearchSourceFields; + equation: string; + interval?: string; + filters?: Filter[]; + groupBy?: string[] | string; +} + +export interface RuleSearchSourceFields extends SerializedSearchSourceFields { + query?: Query; + filter?: Array>; +} + +interface LensItemParams { + type: string; + searchConfiguration: RuleSearchSourceFields; + equation: string; + interval?: string; + filters?: Filter[]; + groupBy?: string[] | string; +} + +const defaultQuery: Query = { + language: 'kuery', + query: '', +}; + +export const LensFieldFormat = { + NUMBER: 'number', + PERCENT: 'percent', + BITS: 'bits', +} as const; + +export function LensWidget({ + timeRange, + searchConfiguration, + equation, + interval, + filters, + groupBy, +}: Props) { + const { + dependencies: { + start: { lens, data }, + }, + } = useKibana(); + + const [attributes, setAttributes] = useState(); + const [chartLoading, setChartLoading] = useState(false); + + const formulaAsync = useAsync(() => { + return lens.stateHelperApi(); + }, [lens]); + + const [dataView, setDataView] = useState(); + const [, setDataViewError] = useState(); + + useEffect(() => { + const initDataView = async () => { + const ruleSearchConfiguration = searchConfiguration; + try { + const createdSearchSource = await data.search.searchSource.create(ruleSearchConfiguration); + setDataView(createdSearchSource.getField('index')); + } catch (error) { + setDataViewError(error); + } + }; + + initDataView(); + }, [data.search.searchSource, searchConfiguration]); + + // Handle Lens error + useEffect(() => { + // Lens does not expose or provide a way to check if there is an error in the chart, yet. + // To work around this, we check if the element with class 'lnsEmbeddedError' is found in the DOM. + setTimeout(function () { + const errorDiv = document.querySelector('.lnsEmbeddedError'); + if (errorDiv) { + const paragraphElements = errorDiv.querySelectorAll('p'); + if (!paragraphElements || paragraphElements.length < 2) return; + paragraphElements[0].innerText = i18n.translate( + 'xpack.investigateApp.defaultChart.error_equation.title', + { + defaultMessage: 'An error occurred while rendering the chart', + } + ); + paragraphElements[1].innerText = i18n.translate( + 'xpack.investigateApp.defaultChart.error_equation.description', + { + defaultMessage: 'Check the equation.', + } + ); + } + }); + }, [chartLoading, attributes]); + + useEffect(() => { + if (!formulaAsync.value || !dataView || !equation) { + return; + } + const baseLayer = { + type: 'formula', + value: equation, + label: equation, + groupBy, + }; + const xYDataLayerOptions: XYLayerOptions = { + buckets: { + type: 'date_histogram', + params: { + interval, + }, + }, + seriesType: 'bar', + }; + + if (groupBy && groupBy?.length) { + xYDataLayerOptions.breakdown = { + type: 'top_values', + field: groupBy[0], + params: { + size: 3, + secondaryFields: (groupBy as string[]).slice(1), + accuracyMode: false, + }, + }; + } + + const xyDataLayer = new XYDataLayer({ + data: [baseLayer].map((layer) => ({ + type: layer.type, + value: layer.value, + label: layer.label, + })), + options: xYDataLayerOptions, + }); + + const layers: Array = [ + xyDataLayer, + ]; + + const attributesLens = new LensAttributesBuilder({ + visualization: new XYChart({ + visualOptions: { + axisTitlesVisibilitySettings: { + x: false, + yLeft: false, + yRight: false, + }, + legend: { + isVisible: false, + position: 'right', + }, + }, + layers, + formulaAPI: formulaAsync.value.formula, + dataView, + }), + }).build(); + const lensBuilderAtt = { ...attributesLens, type: 'lens' }; + setAttributes(lensBuilderAtt); + }, [searchConfiguration, equation, groupBy, interval, dataView, formulaAsync.value]); + + if (!dataView || !attributes || !timeRange) { + return ( +
+ + } + /> +
+ ); + } + + return ( +
+ +
+ ); +} + +export function registerLensItem({ + dependencies: { + setup: { investigate }, + }, +}: Options) { + investigate.registerItemDefinition({ + type: 'lens', + generate: async () => { + return {}; + }, + render: (option: { itemParams: LensItemParams; globalParams: GlobalWidgetParameters }) => { + const { itemParams, globalParams } = option; + return ( + + ); + }, + }); +} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/items/register_items.ts b/x-pack/plugins/observability_solution/investigate_app/public/items/register_items.ts index ff0304105a0b0..4ae017f5bbcdf 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/items/register_items.ts +++ b/x-pack/plugins/observability_solution/investigate_app/public/items/register_items.ts @@ -9,6 +9,7 @@ import type { InvestigateAppServices } from '../services/types'; import type { InvestigateAppSetupDependencies, InvestigateAppStartDependencies } from '../types'; import { registerEmbeddableItem } from './embeddable_item/register_embeddable_item'; import { registerEsqlItem } from './esql_item/register_esql_item'; +import { registerLensItem } from './lens_item/register_lens_item'; export interface Options { dependencies: { @@ -21,4 +22,5 @@ export interface Options { export function registerItems(options: Options) { registerEsqlItem(options); registerEmbeddableItem(options); + registerLensItem(options); } diff --git a/x-pack/plugins/observability_solution/investigate_app/tsconfig.json b/x-pack/plugins/observability_solution/investigate_app/tsconfig.json index 29b4985896ee2..b452b80b821ca 100644 --- a/x-pack/plugins/observability_solution/investigate_app/tsconfig.json +++ b/x-pack/plugins/observability_solution/investigate_app/tsconfig.json @@ -56,5 +56,7 @@ "@kbn/shared-ux-router", "@kbn/investigation-shared", "@kbn/core-security-common", + "@kbn/lens-embeddable-utils", + "@kbn/i18n-react", ], } diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx index 6ea43b165fe7a..5d20f8830799b 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx @@ -30,10 +30,14 @@ import { ALERT_END, ALERT_RULE_TYPE_ID, OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, + ALERT_GROUP, } from '@kbn/rule-data-utils'; import { v4 as uuidv4 } from 'uuid'; import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-time-range-util'; +import { CreateInvestigationResponse } from '@kbn/investigation-shared'; +import { RuleTypeParams } from '@kbn/alerting-plugin/common'; +import { Group } from '@kbn/observability-alerting-rule-utils'; import { useKibana } from '../../../utils/kibana_react'; import { useFetchRule } from '../../../hooks/use_fetch_rule'; import type { TopAlert } from '../../../typings/alerts'; @@ -41,6 +45,9 @@ import { paths } from '../../../../common/locators/paths'; import { useBulkUntrackAlerts } from '../hooks/use_bulk_untrack_alerts'; import { useCreateInvestigation } from '../hooks/use_create_investigation'; import { useFetchInvestigationsByAlert } from '../hooks/use_fetch_investigations_by_alert'; +import { useAddInvestigationItem } from '../hooks/use_add_investigation_item'; +import { AlertParams } from '../../../components/custom_threshold/types'; +import { generateInvestigationItem } from '../../../utils/investigation_item_helper'; export interface HeaderActionsProps { alert: TopAlert | null; @@ -125,10 +132,36 @@ export function HeaderActions({ }; const { mutateAsync: createInvestigation } = useCreateInvestigation(); + const { mutateAsync: addInvestigationItem } = useAddInvestigationItem(); const alertStart = alert?.fields[ALERT_START]; const alertEnd = alert?.fields[ALERT_END]; + const addChartsToInvestigation = async (investigationDetails: CreateInvestigationResponse) => { + if ( + rule && + alert && + alert.fields[ALERT_RULE_TYPE_ID] === OBSERVABILITY_THRESHOLD_RULE_TYPE_ID + ) { + const ruleParams = rule.params as RuleTypeParams & AlertParams; + + for (let index = 0; index < ruleParams.criteria.length; index++) { + const criterion = ruleParams.criteria[index]; + const item = generateInvestigationItem( + criterion, + ruleParams.searchConfiguration, + alert.fields[ALERT_RULE_TYPE_ID], + ruleParams.groupBy, + alert.fields[ALERT_GROUP] as Group[] + ); + + if (item) { + await addInvestigationItem({ investigationId: investigationDetails.id, item }); + } + } + } + }; + const createOrOpenInvestigation = async () => { if (!alert) return; @@ -152,6 +185,8 @@ export function HeaderActions({ }, }); + await addChartsToInvestigation(investigationResponse); + navigateToApp('investigate', { path: `/${investigationResponse.id}`, replace: false }); } else { navigateToApp('investigate', { diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_add_investigation_item.ts b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_add_investigation_item.ts new file mode 100644 index 0000000000000..bb783e202f156 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_add_investigation_item.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { IHttpFetchError, ResponseErrorBody } from '@kbn/core/public'; +import { + CreateInvestigationItemParams, + CreateInvestigationItemResponse, +} from '@kbn/investigation-shared'; +import { useMutation } from '@tanstack/react-query'; +import { useKibana } from '../../../utils/kibana_react'; + +type ServerError = IHttpFetchError; + +export function useAddInvestigationItem() { + const { + http, + notifications: { toasts }, + } = useKibana().services; + + return useMutation< + CreateInvestigationItemResponse, + ServerError, + { investigationId: string; item: CreateInvestigationItemParams }, + { investigationId: string } + >( + ['addInvestigationItem'], + ({ investigationId, item }) => { + const body = JSON.stringify(item); + return http.post( + `/api/observability/investigations/${investigationId}/items`, + { body, version: '2023-10-31' } + ); + }, + { + onSuccess: (response, {}) => { + toasts.addSuccess('Item added to investigation'); + }, + onError: (error, {}, context) => { + toasts.addError(new Error(error.body?.message ?? 'An error occurred'), { title: 'Error' }); + }, + } + ); +} diff --git a/x-pack/plugins/observability_solution/observability/public/utils/investigation_item_helper.ts b/x-pack/plugins/observability_solution/observability/public/utils/investigation_item_helper.ts new file mode 100644 index 0000000000000..5ffaa234b3d97 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability/public/utils/investigation_item_helper.ts @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Group } from '@kbn/observability-alerting-rule-utils'; +import { OBSERVABILITY_THRESHOLD_RULE_TYPE_ID } from '@kbn/rule-data-utils'; +import { + CustomThresholdExpressionMetric, + CustomThresholdSearchSourceFields, +} from '../../common/custom_threshold_rule/types'; +import { MetricExpression } from '../components/custom_threshold/types'; +import { getGroupFilters } from '..'; + +const AggMappingForLens: Record = { + avg: 'average', + cardinality: 'unique_count', +}; + +const genLensEqForCustomThresholdRule = (criterion: MetricExpression) => { + const metricNameResolver: Record = {}; + + criterion.metrics.forEach( + (metric: CustomThresholdExpressionMetric) => + (metricNameResolver[metric.name] = `${ + AggMappingForLens[metric.aggType] ? AggMappingForLens[metric.aggType] : metric.aggType + }(${metric.field ? metric.field : metric.filter ? metric.filter : ''})`) + ); + + let equation = criterion.equation + ? criterion.equation + : criterion.metrics.map((m) => m.name).join('+'); + + Object.keys(metricNameResolver) + .sort() + .reverse() + .forEach((metricName) => { + equation = equation.replaceAll(metricName, metricNameResolver[metricName]); + }); + + return equation; +}; + +export const generateInvestigationItem = ( + criterion: MetricExpression, + searchConfiguration: CustomThresholdSearchSourceFields, + ruleTypeId: string, + groupBy?: string | string[], + groups?: Group[] +) => { + if (ruleTypeId === OBSERVABILITY_THRESHOLD_RULE_TYPE_ID) { + const equation = genLensEqForCustomThresholdRule(criterion); + const filters = searchConfiguration.filter || []; + const additionalFilters = getGroupFilters(groups); + const interval = `${criterion.timeSize}${criterion.timeUnit}`; + + const item = { + title: equation, + type: 'lens', + params: { + filters: [...filters, ...additionalFilters], + equation, + interval, + searchConfiguration, + groupBy, + }, + }; + + return item; + } +}; From 82c31f9c08af51e10108635e0856d7c44ddf7d11 Mon Sep 17 00:00:00 2001 From: Alex Szabo Date: Thu, 5 Sep 2024 09:55:40 +0200 Subject: [PATCH 15/99] skip flaky test: https://github.com/elastic/kibana/issues/178001 (#192150) ## Summary Manually skipping for https://github.com/elastic/kibana/issues/178001 --- .../public/components/custom_fields/text/configure.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/public/components/custom_fields/text/configure.test.tsx b/x-pack/plugins/cases/public/components/custom_fields/text/configure.test.tsx index 455163f225a2b..2cb7618f7f18a 100644 --- a/x-pack/plugins/cases/public/components/custom_fields/text/configure.test.tsx +++ b/x-pack/plugins/cases/public/components/custom_fields/text/configure.test.tsx @@ -44,7 +44,8 @@ describe('Configure ', () => { }); }); - it('updates field options with default value correctly when not required', async () => { + // Flaky: https://github.com/elastic/kibana/issues/178001 + it.skip('updates field options with default value correctly when not required', async () => { render( From c82ca8efb82ef132ed894cdbadc917f582486fba Mon Sep 17 00:00:00 2001 From: Robert Jaszczurek <92210485+rbrtj@users.noreply.github.com> Date: Thu, 5 Sep 2024 10:13:57 +0200 Subject: [PATCH 16/99] [ML] Links to the Single Metric Viewer from the Annotations and Forecasts table fix (#192000) ## Summary Fix for: [#191936](https://github.com/elastic/kibana/issues/191936) Fixes navigation from the Forecasts & Annotations table to the Single Metric Viewer. Added functional tests. Tested on 8.15 - issue doesn't exist, it was probably introduced in [#189729](https://github.com/elastic/kibana/pull/189729) ### 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 --- .../annotations_table/annotations_table.js | 8 +++- .../forecasts_table/forecasts_table.js | 4 +- .../job_expanded_details.ts | 14 ++++++- .../services/ml/job_expanded_details.ts | 37 ++++++++++++++----- 4 files changed, 50 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js b/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js index b5842e479ba11..31ac00c1f79db 100644 --- a/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js +++ b/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js @@ -223,6 +223,7 @@ class AnnotationsTableUI extends Component { openSingleMetricView = async (annotation = {}) => { const { services: { + chrome: { recentlyAccessed }, application: { navigateToUrl }, share, }, @@ -307,7 +308,12 @@ class AnnotationsTableUI extends Component { { absolute: true } ); - addItemToRecentlyAccessed('timeseriesexplorer', job.job_id, singleMetricViewerLink); + addItemToRecentlyAccessed( + 'timeseriesexplorer', + job.job_id, + singleMetricViewerLink, + recentlyAccessed + ); await navigateToUrl(singleMetricViewerLink); }; diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/forecasts_table/forecasts_table.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/forecasts_table/forecasts_table.js index 976ea8bc9968b..5f1cbb1c76ca0 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/forecasts_table/forecasts_table.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/forecasts_table/forecasts_table.js @@ -89,6 +89,7 @@ export class ForecastsTable extends Component { async openSingleMetricView(forecast) { const { services: { + chrome: { recentlyAccessed }, application: { navigateToUrl }, share, }, @@ -156,7 +157,8 @@ export class ForecastsTable extends Component { addItemToRecentlyAccessed( 'timeseriesexplorer', this.props.job.job_id, - singleMetricViewerForecastLink + singleMetricViewerForecastLink, + recentlyAccessed ); await navigateToUrl(singleMetricViewerForecastLink); } diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/job_expanded_details.ts b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/job_expanded_details.ts index c1c8eee13ba22..e48ca875bb1f2 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/job_expanded_details.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/job_expanded_details.ts @@ -83,11 +83,21 @@ export default function ({ getService }: FtrProviderContext) { await ml.jobExpandedDetails.assertJobRowCalendars(jobId, [calendarId]); }); - it('expanded row with forecast should display open forecast button', async () => { - await ml.jobExpandedDetails.assertForecastElements(jobId); + it('expanded row with forecast should navigate to Single Metric Viewer on button click', async () => { + await ml.jobExpandedDetails.openForecastJob(jobId); + }); + + it('expanded row with annotations should navigate to Single Metric Viewer on button click', async () => { + await ml.navigation.navigateToJobManagement(); + + const annotationsFromApi = await ml.api.getAnnotations(jobId); + + await ml.jobExpandedDetails.openAnnotationInSingleMetricViewer(jobId, annotationsFromApi); }); it('expanded row with annotations can be edited', async () => { + await ml.navigation.navigateToJobManagement(); + const annotationsFromApi = await ml.api.getAnnotations(jobId); await ml.jobExpandedDetails.editAnnotation(jobId, 'edited annotation', annotationsFromApi); diff --git a/x-pack/test/functional/services/ml/job_expanded_details.ts b/x-pack/test/functional/services/ml/job_expanded_details.ts index 44e8cb9c09bfd..d9c82d72eabc4 100644 --- a/x-pack/test/functional/services/ml/job_expanded_details.ts +++ b/x-pack/test/functional/services/ml/job_expanded_details.ts @@ -46,12 +46,11 @@ export function MachineLearningJobExpandedDetailsProvider( }); }, - async assertForecastElements(jobId: string): Promise { + async openForecastJob(jobId: string): Promise { await jobTable.ensureDetailsOpen(jobId); await this.openForecastTab(jobId); - await testSubjects.existOrFail('mlJobListForecastTabOpenSingleMetricViewButton', { - timeout: 5_000, - }); + await testSubjects.click('mlJobListForecastTabOpenSingleMetricViewButton', 5000); + await testSubjects.existOrFail('mlSingleMetricViewerChart'); }, async clearSearchButton() { @@ -61,16 +60,36 @@ export function MachineLearningJobExpandedDetailsProvider( } }, + async assertAnnotationsFromApi(annotationsFromApi: any) { + const length = annotationsFromApi.length; + expect(length).to.eql( + 1, + `Expect annotations from api to have length of 1, but got [${length}]` + ); + }, + + async openAnnotationInSingleMetricViewer( + jobId: string, + annotationsFromApi: any + ): Promise { + await this.assertAnnotationsFromApi(annotationsFromApi); + + const { _id: annotationId }: { _id: string } = annotationsFromApi[0]; + + await jobTable.ensureDetailsOpen(jobId); + await jobTable.openAnnotationsTab(jobId); + await this.clearSearchButton(); + await jobAnnotationsTable.ensureAnnotationsActionsMenuOpen(annotationId); + await testSubjects.click('mlAnnotationsActionOpenInSingleMetricViewer'); + await testSubjects.existOrFail('mlSingleMetricViewerChart'); + }, + async editAnnotation( jobId: string, newAnnotationText: string, annotationsFromApi: any ): Promise { - const length = annotationsFromApi.length; - expect(length).to.eql( - 1, - `Expect annotions from api to have length of 1, but got [${length}]` - ); + await this.assertAnnotationsFromApi(annotationsFromApi); await jobTable.ensureDetailsOpen(jobId); await jobTable.openAnnotationsTab(jobId); From 75d0c9085ac923262e7c70ab92d0496beb9e7696 Mon Sep 17 00:00:00 2001 From: Robert Jaszczurek <92210485+rbrtj@users.noreply.github.com> Date: Thu, 5 Sep 2024 10:15:17 +0200 Subject: [PATCH 17/99] [ML] Anomaly explorer: Fix the order of the coordinates displayed on the map tooltip (#192077) ## Summary Fix for [#190123](https://github.com/elastic/kibana/issues/190123) Sync the order of the coordinates displayed in the table with those shown in the tooltip in the anomaly explorer map. ![Zrzut ekranu 2024-09-4 o 14 12 19](https://github.com/user-attachments/assets/da304be3-a756-444e-ae42-04e307194042) --- .../application/explorer/explorer_charts/map_config.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/map_config.ts b/x-pack/plugins/ml/public/application/explorer/explorer_charts/map_config.ts index 8991ba6733e3b..f3aa8ef601a02 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/map_config.ts +++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/map_config.ts @@ -22,17 +22,14 @@ function getAnomalyFeatures( const geoResults = anomaly.geo_results || (anomaly?.causes && anomaly?.causes[0]?.geo_results); const coordinateStr = geoResults && geoResults[type]; if (coordinateStr !== undefined) { - // Must reverse coordinates here. Map expects [lon, lat] - anomalies are stored as [lat, lon] for lat_lon jobs - const coordinates = coordinateStr - .split(',') - .map((point: string) => Number(point)) - .reverse(); + const coordinates = coordinateStr.split(',').map((point: string) => Number(point)); anomalyFeatures.push({ type: FEATURE, geometry: { type: POINT, - coordinates, + // Must reverse coordinates here. Map expects [lon, lat] - anomalies are stored as [lat, lon] for lat_lon jobs + coordinates: coordinates.toReversed(), }, properties: { record_score: Math.floor(anomaly.record_score), From 43a4a8c3c44595a9d4f8d0ab4588c57daf5697cc Mon Sep 17 00:00:00 2001 From: Robert Jaszczurek <92210485+rbrtj@users.noreply.github.com> Date: Thu, 5 Sep 2024 10:17:27 +0200 Subject: [PATCH 18/99] [ML] Transforms: Adds confirmation dialog when deleting a transform from warning banner (#192080) ## Summary Changes for [#178972](https://github.com/elastic/kibana/issues/178972), adding in a confirmation dialog when deleting a transform from the warning banner in the management list, shown for example when the configuration for a transform has been deleted. Multiple transforms deletion: https://github.com/user-attachments/assets/554bf52d-c477-4fc2-94ec-473fb708edc8 Single transform deletion: ![image](https://github.com/user-attachments/assets/3f5a8c58-f520-4280-9205-0485e2b79866) --- .../dangling_task_warning.tsx | 116 ++++++++++++++++++ .../transform_management_section.tsx | 52 +------- 2 files changed, 118 insertions(+), 50 deletions(-) create mode 100644 x-pack/plugins/transform/public/app/sections/transform_management/components/dangling_task_warning/dangling_task_warning.tsx diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/dangling_task_warning/dangling_task_warning.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/dangling_task_warning/dangling_task_warning.tsx new file mode 100644 index 0000000000000..07819bd01b5b3 --- /dev/null +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/dangling_task_warning/dangling_task_warning.tsx @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FC } from 'react'; +import React, { useState } from 'react'; +import { + EuiCallOut, + EuiButton, + EuiConfirmModal, + EUI_MODAL_CONFIRM_BUTTON, + EuiSpacer, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { useDeleteTransforms } from '../../../../hooks'; +import { TRANSFORM_STATE } from '../../../../../../common/constants'; + +export const DanglingTasksWarning: FC<{ + transformIdsWithoutConfig?: string[]; +}> = ({ transformIdsWithoutConfig }) => { + const [isModalVisible, setIsModalVisible] = useState(false); + const deleteTransforms = useDeleteTransforms(); + + const closeModal = () => setIsModalVisible(false); + const openModal = () => setIsModalVisible(true); + + const confirmDelete = () => { + if (transformIdsWithoutConfig) { + deleteTransforms( + // If transform task doesn't have any corresponding config + // we won't know what the destination index or data view would be + // and should be force deleted + { + transformsInfo: transformIdsWithoutConfig.map((id) => ({ + id, + state: TRANSFORM_STATE.FAILED, + })), + deleteDestIndex: false, + deleteDestDataView: false, + forceDelete: true, + } + ); + } + closeModal(); + }; + + if (!transformIdsWithoutConfig || transformIdsWithoutConfig.length === 0) { + return null; + } + + const isBulkAction = transformIdsWithoutConfig.length > 1; + + const bulkDeleteModalTitle = i18n.translate( + 'xpack.transform.transformList.bulkDeleteModalTitle', + { + defaultMessage: 'Delete {count} {count, plural, one {transform} other {transforms}}?', + values: { count: transformIdsWithoutConfig.length }, + } + ); + const deleteModalTitle = i18n.translate('xpack.transform.transformList.deleteModalTitle', { + defaultMessage: 'Delete {transformId}?', + values: { transformId: transformIdsWithoutConfig[0] }, + }); + + return ( + <> + +

+ +

+ + + +
+ + {isModalVisible && ( + + )} + + ); +}; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx index 5f703a57dff2c..e192f736968da 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx @@ -8,7 +8,6 @@ import React, { type FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { - EuiButton, EuiButtonEmpty, EuiCallOut, EuiModal, @@ -33,12 +32,10 @@ import { isTransformStats } from '../../../../common/types/transform_stats'; import { useGetTransformsStats } from '../../hooks/use_get_transform_stats'; import { useEnabledFeatures } from '../../serverless_context'; import { needsReauthorization } from '../../common/reauthorization_utils'; -import { TRANSFORM_STATE } from '../../../../common/constants'; import { TRANSFORM_LIST_COLUMN } from '../../common'; import { useDocumentationLinks, - useDeleteTransforms, useTransformCapabilities, useGetTransforms, useGetTransformNodes, @@ -56,6 +53,7 @@ import { getAlertRuleManageContext, TransformAlertFlyoutWrapper, } from '../../../alerting/transform_alerting_flyout'; +import { DanglingTasksWarning } from './components/dangling_task_warning/dangling_task_warning'; const getDefaultTransformListState = (): ListingPageUrlState => ({ pageIndex: 0, @@ -98,8 +96,6 @@ export const TransformManagement: FC = () => { getDefaultTransformListState() ); - const deleteTransforms = useDeleteTransforms(); - const { isInitialLoading: transformNodesInitialLoading, error: transformNodesErrorMessage, @@ -312,51 +308,7 @@ export const TransformManagement: FC = () => { - {transformIdsWithoutConfig ? ( - <> - -

- -

- - deleteTransforms( - // If transform task doesn't have any corresponding config - // we won't know what the destination index or data view would be - // and should be force deleted - { - transformsInfo: transformIdsWithoutConfig.map((id) => ({ - id, - state: TRANSFORM_STATE.FAILED, - })), - deleteDestIndex: false, - deleteDestDataView: false, - forceDelete: true, - } - ) - } - > - - -
- - - ) : null} + {(transformNodes > 0 || transforms.length > 0) && ( Date: Thu, 5 Sep 2024 10:18:30 +0200 Subject: [PATCH 19/99] [Dashboard] Fix add panels order of items !! (#192082) ## Summary Fixes part of https://github.com/elastic/kibana/issues/190853 !! Combines synthetics and SLO embeddables under common observability group !! ### After image ### Before image --- .../common/embeddable_grouping.ts} | 10 ++++++---- .../observability_shared/common/index.ts | 2 ++ .../ui_actions/create_alerts_panel_action.tsx | 6 +++--- .../ui_actions/create_burn_rate_panel_action.tsx | 6 +++--- .../ui_actions/create_error_budget_action.tsx | 6 +++--- .../ui_actions/create_overview_panel_action.tsx | 6 +++--- .../public/apps/embeddables/constants.ts | 15 --------------- .../create_monitors_overview_panel_action.tsx | 7 ++++--- .../create_stats_overview_panel_action.tsx | 7 ++++--- .../plugins/translations/translations/fr-FR.json | 1 - .../plugins/translations/translations/ja-JP.json | 1 - .../plugins/translations/translations/zh-CN.json | 1 - .../apps/slo/embeddables/overview_embeddable.ts | 6 +++--- 13 files changed, 31 insertions(+), 43 deletions(-) rename x-pack/plugins/observability_solution/{slo/public/embeddable/slo/common/constants.ts => observability_shared/common/embeddable_grouping.ts} (68%) diff --git a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/common/constants.ts b/x-pack/plugins/observability_solution/observability_shared/common/embeddable_grouping.ts similarity index 68% rename from x-pack/plugins/observability_solution/slo/public/embeddable/slo/common/constants.ts rename to x-pack/plugins/observability_solution/observability_shared/common/embeddable_grouping.ts index bfb65b58f3158..dba342aa71306 100644 --- a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/common/constants.ts +++ b/x-pack/plugins/observability_solution/observability_shared/common/embeddable_grouping.ts @@ -4,17 +4,19 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import { i18n } from '@kbn/i18n'; -export const COMMON_SLO_GROUPING = [ +export const COMMON_OBSERVABILITY_GROUPING = [ { - id: 'slos', + id: 'observability', getDisplayName: () => - i18n.translate('xpack.slo.common.constants.grouping.legacy', { + i18n.translate('xpack.observabilityShared.common.constants.grouping', { defaultMessage: 'Observability', }), getIconType: () => { - return 'visGauge'; + return 'online'; }, + order: -1, }, ]; diff --git a/x-pack/plugins/observability_solution/observability_shared/common/index.ts b/x-pack/plugins/observability_solution/observability_shared/common/index.ts index 7889eda66bd4a..083bcdd2debde 100644 --- a/x-pack/plugins/observability_solution/observability_shared/common/index.ts +++ b/x-pack/plugins/observability_solution/observability_shared/common/index.ts @@ -188,3 +188,5 @@ export { TopNFunctionsLocatorDefinition, HOSTS_LOCATOR_ID, } from './locators'; + +export { COMMON_OBSERVABILITY_GROUPING } from './embeddable_grouping'; diff --git a/x-pack/plugins/observability_solution/slo/public/ui_actions/create_alerts_panel_action.tsx b/x-pack/plugins/observability_solution/slo/public/ui_actions/create_alerts_panel_action.tsx index 63926aa24cd82..68e985d7d5580 100644 --- a/x-pack/plugins/observability_solution/slo/public/ui_actions/create_alerts_panel_action.tsx +++ b/x-pack/plugins/observability_solution/slo/public/ui_actions/create_alerts_panel_action.tsx @@ -12,21 +12,21 @@ import { type UiActionsActionDefinition, } from '@kbn/ui-actions-plugin/public'; import { EmbeddableApiContext } from '@kbn/presentation-publishing'; +import { COMMON_OBSERVABILITY_GROUPING } from '@kbn/observability-shared-plugin/common'; import { ADD_SLO_ALERTS_ACTION_ID, SLO_ALERTS_EMBEDDABLE_ID, } from '../embeddable/slo/alerts/constants'; import { SloPublicPluginsStart, SloPublicStart } from '..'; -import { COMMON_SLO_GROUPING } from '../embeddable/slo/common/constants'; export function createAddAlertsPanelAction( getStartServices: CoreSetup['getStartServices'] ): UiActionsActionDefinition { return { id: ADD_SLO_ALERTS_ACTION_ID, - grouping: COMMON_SLO_GROUPING, + grouping: COMMON_OBSERVABILITY_GROUPING, getIconType: () => 'alert', - order: 20, + order: 10, isCompatible: async ({ embeddable }) => { return apiIsPresentationContainer(embeddable); }, diff --git a/x-pack/plugins/observability_solution/slo/public/ui_actions/create_burn_rate_panel_action.tsx b/x-pack/plugins/observability_solution/slo/public/ui_actions/create_burn_rate_panel_action.tsx index 0b00d33b4cf6a..02490cf1bf7f8 100644 --- a/x-pack/plugins/observability_solution/slo/public/ui_actions/create_burn_rate_panel_action.tsx +++ b/x-pack/plugins/observability_solution/slo/public/ui_actions/create_burn_rate_panel_action.tsx @@ -12,20 +12,20 @@ import { IncompatibleActionError, type UiActionsActionDefinition, } from '@kbn/ui-actions-plugin/public'; +import { COMMON_OBSERVABILITY_GROUPING } from '@kbn/observability-shared-plugin/common'; import { SloPublicPluginsStart, SloPublicStart } from '..'; import { ADD_BURN_RATE_ACTION_ID, SLO_BURN_RATE_EMBEDDABLE_ID, } from '../embeddable/slo/burn_rate/constants'; -import { COMMON_SLO_GROUPING } from '../embeddable/slo/common/constants'; export function createBurnRatePanelAction( getStartServices: CoreSetup['getStartServices'] ): UiActionsActionDefinition { return { id: ADD_BURN_RATE_ACTION_ID, - grouping: COMMON_SLO_GROUPING, - order: 30, + grouping: COMMON_OBSERVABILITY_GROUPING, + order: 20, getIconType: () => 'visGauge', isCompatible: async ({ embeddable }) => { return apiIsPresentationContainer(embeddable); diff --git a/x-pack/plugins/observability_solution/slo/public/ui_actions/create_error_budget_action.tsx b/x-pack/plugins/observability_solution/slo/public/ui_actions/create_error_budget_action.tsx index 8d311bfdce70b..9ba0b7a7a8677 100644 --- a/x-pack/plugins/observability_solution/slo/public/ui_actions/create_error_budget_action.tsx +++ b/x-pack/plugins/observability_solution/slo/public/ui_actions/create_error_budget_action.tsx @@ -12,19 +12,19 @@ import { type UiActionsActionDefinition, } from '@kbn/ui-actions-plugin/public'; import { EmbeddableApiContext } from '@kbn/presentation-publishing'; +import { COMMON_OBSERVABILITY_GROUPING } from '@kbn/observability-shared-plugin/common'; import { ADD_SLO_ERROR_BUDGET_ACTION_ID, SLO_ERROR_BUDGET_ID, } from '../embeddable/slo/error_budget/constants'; import { SloPublicPluginsStart, SloPublicStart } from '..'; -import { COMMON_SLO_GROUPING } from '../embeddable/slo/common/constants'; export function createAddErrorBudgetPanelAction( getStartServices: CoreSetup['getStartServices'] ): UiActionsActionDefinition { return { id: ADD_SLO_ERROR_BUDGET_ACTION_ID, - grouping: COMMON_SLO_GROUPING, - order: 10, + grouping: COMMON_OBSERVABILITY_GROUPING, + order: 6, getIconType: () => 'visLine', isCompatible: async ({ embeddable }) => { return apiIsPresentationContainer(embeddable); diff --git a/x-pack/plugins/observability_solution/slo/public/ui_actions/create_overview_panel_action.tsx b/x-pack/plugins/observability_solution/slo/public/ui_actions/create_overview_panel_action.tsx index 49d2d269d4cdd..c4b6e5009382d 100644 --- a/x-pack/plugins/observability_solution/slo/public/ui_actions/create_overview_panel_action.tsx +++ b/x-pack/plugins/observability_solution/slo/public/ui_actions/create_overview_panel_action.tsx @@ -12,20 +12,20 @@ import { type UiActionsActionDefinition, } from '@kbn/ui-actions-plugin/public'; import { EmbeddableApiContext } from '@kbn/presentation-publishing'; +import { COMMON_OBSERVABILITY_GROUPING } from '@kbn/observability-shared-plugin/common'; import { ADD_SLO_OVERVIEW_ACTION_ID, SLO_OVERVIEW_EMBEDDABLE_ID, } from '../embeddable/slo/overview/constants'; import { SloPublicPluginsStart, SloPublicStart } from '..'; -import { COMMON_SLO_GROUPING } from '../embeddable/slo/common/constants'; export function createOverviewPanelAction( getStartServices: CoreSetup['getStartServices'] ): UiActionsActionDefinition { return { id: ADD_SLO_OVERVIEW_ACTION_ID, - grouping: COMMON_SLO_GROUPING, - order: 30, + grouping: COMMON_OBSERVABILITY_GROUPING, + order: 20, getIconType: () => 'visGauge', isCompatible: async ({ embeddable }) => { return apiIsPresentationContainer(embeddable); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/embeddables/constants.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/embeddables/constants.ts index 5afcf2d3026b4..2299452f4accd 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/embeddables/constants.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/embeddables/constants.ts @@ -5,22 +5,7 @@ * 2.0. */ -import { i18n } from '@kbn/i18n'; - export const SYNTHETICS_STATS_OVERVIEW_EMBEDDABLE = 'SYNTHETICS_STATS_OVERVIEW_EMBEDDABLE'; export const SYNTHETICS_MONITORS_EMBEDDABLE = 'SYNTHETICS_MONITORS_EMBEDDABLE'; -export const COMMON_SYNTHETICS_GROUPING = [ - { - id: 'synthetics', - getDisplayName: () => - i18n.translate('xpack.synthetics.common.constants.grouping.legacy', { - defaultMessage: 'Synthetics', - }), - getIconType: () => { - return 'online'; - }, - }, -]; - export const ALL_VALUE = '*'; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/embeddables/ui_actions/create_monitors_overview_panel_action.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/embeddables/ui_actions/create_monitors_overview_panel_action.tsx index aa7355c4e1fec..c3f935add49c4 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/embeddables/ui_actions/create_monitors_overview_panel_action.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/embeddables/ui_actions/create_monitors_overview_panel_action.tsx @@ -12,8 +12,9 @@ import { } from '@kbn/ui-actions-plugin/public'; import { EmbeddableApiContext } from '@kbn/presentation-publishing'; import type { StartServicesAccessor } from '@kbn/core-lifecycle-browser'; +import { COMMON_OBSERVABILITY_GROUPING } from '@kbn/observability-shared-plugin/common'; import { ClientPluginsStart } from '../../../plugin'; -import { COMMON_SYNTHETICS_GROUPING, SYNTHETICS_MONITORS_EMBEDDABLE } from '../constants'; +import { SYNTHETICS_MONITORS_EMBEDDABLE } from '../constants'; export const ADD_SYNTHETICS_MONITORS_OVERVIEW_ACTION_ID = 'CREATE_SYNTHETICS_MONITORS_OVERVIEW_EMBEDDABLE'; @@ -23,8 +24,8 @@ export function createMonitorsOverviewPanelAction( ): UiActionsActionDefinition { return { id: ADD_SYNTHETICS_MONITORS_OVERVIEW_ACTION_ID, - grouping: COMMON_SYNTHETICS_GROUPING, - order: 30, + grouping: COMMON_OBSERVABILITY_GROUPING, + order: 5, getIconType: () => 'play', isCompatible: async ({ embeddable }) => { return apiIsPresentationContainer(embeddable); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/embeddables/ui_actions/create_stats_overview_panel_action.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/embeddables/ui_actions/create_stats_overview_panel_action.tsx index a3b2c67be88fe..9f88e38c3640c 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/embeddables/ui_actions/create_stats_overview_panel_action.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/embeddables/ui_actions/create_stats_overview_panel_action.tsx @@ -11,8 +11,9 @@ import { } from '@kbn/ui-actions-plugin/public'; import { EmbeddableApiContext } from '@kbn/presentation-publishing'; import type { StartServicesAccessor } from '@kbn/core-lifecycle-browser'; +import { COMMON_OBSERVABILITY_GROUPING } from '@kbn/observability-shared-plugin/common'; import { ClientPluginsStart } from '../../../plugin'; -import { COMMON_SYNTHETICS_GROUPING, SYNTHETICS_STATS_OVERVIEW_EMBEDDABLE } from '../constants'; +import { SYNTHETICS_STATS_OVERVIEW_EMBEDDABLE } from '../constants'; export const ADD_SYNTHETICS_OVERVIEW_ACTION_ID = 'CREATE_SYNTHETICS_STATS_OVERVIEW_EMBEDDABLE'; @@ -21,8 +22,8 @@ export function createStatusOverviewPanelAction( ): UiActionsActionDefinition { return { id: ADD_SYNTHETICS_OVERVIEW_ACTION_ID, - grouping: COMMON_SYNTHETICS_GROUPING, - order: 30, + grouping: COMMON_OBSERVABILITY_GROUPING, + order: 5, getIconType: () => 'online', isCompatible: async ({ embeddable }) => { const { compatibilityCheck } = await import('./compatibility_check'); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 760d745ebe0c8..fddb13aa197df 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -41526,7 +41526,6 @@ "xpack.slo.burnRateRuleEditor.h5.chooseASLOToMonitorLabel": "Choisir un SLO pour monitorer", "xpack.slo.burnRateRuleEditor.h5.defineMultipleBurnRateLabel": "Définir des fenêtres du taux d'avancement multiples", "xpack.slo.burnRates.fromRange.label": "{duration}h", - "xpack.slo.common.constants.grouping.legacy": "Observabilité", "xpack.slo.create.errorNotification": "Un problème est survenu lors de la création de {name}", "xpack.slo.deleteConfirmationModal.cancelButtonLabel": "Annuler", "xpack.slo.deleteConfirmationModal.deleteAllButtonLabel": "Supprimer le SLO et toutes les instances", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 366d85478acda..42f9a5fa9125b 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -41512,7 +41512,6 @@ "xpack.slo.burnRateRuleEditor.h5.chooseASLOToMonitorLabel": "監視するSLOを選択", "xpack.slo.burnRateRuleEditor.h5.defineMultipleBurnRateLabel": "複数のバーンレート時間枠を定義", "xpack.slo.burnRates.fromRange.label": "{duration}h", - "xpack.slo.common.constants.grouping.legacy": "Observability", "xpack.slo.create.errorNotification": "{name}の作成中に問題が発生しました", "xpack.slo.deleteConfirmationModal.cancelButtonLabel": "キャンセル", "xpack.slo.deleteConfirmationModal.deleteAllButtonLabel": "SLOとすべてのインスタンスを削除", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 455314827fd7e..5d43e6030af81 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -41555,7 +41555,6 @@ "xpack.slo.burnRateRuleEditor.h5.chooseASLOToMonitorLabel": "选择要监测的 SLO", "xpack.slo.burnRateRuleEditor.h5.defineMultipleBurnRateLabel": "定义多个消耗速度窗口", "xpack.slo.burnRates.fromRange.label": "{duration}h", - "xpack.slo.common.constants.grouping.legacy": "Observability", "xpack.slo.create.errorNotification": "创建 {name} 时出现问题", "xpack.slo.deleteConfirmationModal.cancelButtonLabel": "取消", "xpack.slo.deleteConfirmationModal.deleteAllButtonLabel": "删除 SLO 和所有实例", diff --git a/x-pack/test/functional/apps/slo/embeddables/overview_embeddable.ts b/x-pack/test/functional/apps/slo/embeddables/overview_embeddable.ts index 3624513b7cbb7..adf2339323fe2 100644 --- a/x-pack/test/functional/apps/slo/embeddables/overview_embeddable.ts +++ b/x-pack/test/functional/apps/slo/embeddables/overview_embeddable.ts @@ -20,7 +20,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const sloUi = getService('sloUi'); const dashboardAddPanel = getService('dashboardAddPanel'); - describe('overview embeddable', function () { + describe('OverviewEmbeddable', function () { before(async () => { await loadTestData(getService); await slo.createUser(); @@ -40,7 +40,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('Single SLO', function () { it('should open SLO configuration flyout', async () => { await dashboardAddPanel.clickEditorMenuButton(); - await dashboardAddPanel.verifyEmbeddableFactoryGroupExists('slos'); + await dashboardAddPanel.verifyEmbeddableFactoryGroupExists('observability'); await dashboardAddPanel.clickAddNewPanelFromUIActionLink('SLO Overview'); await sloUi.common.assertSloOverviewConfigurationExists(); }); @@ -68,7 +68,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('Group of SLOs', function () { it('can select Group Overview mode in the Flyout configuration', async () => { await dashboardAddPanel.clickEditorMenuButton(); - await dashboardAddPanel.verifyEmbeddableFactoryGroupExists('slos'); + await dashboardAddPanel.verifyEmbeddableFactoryGroupExists('observability'); await dashboardAddPanel.clickAddNewPanelFromUIActionLink('SLO Overview'); await sloUi.common.clickOverviewMode(); await sloUi.common.assertSloConfigurationGroupOverviewModeIsSelected(); From 8be089be5921fc6de44e5097e78c5de67fb0725e Mon Sep 17 00:00:00 2001 From: Mark Hopkin Date: Thu, 5 Sep 2024 09:43:40 +0100 Subject: [PATCH 20/99] [Entity Analytics] MKI test failure fixes (#190182) ## Summary closes [#10176](https://github.com/elastic/security-team/issues/10176) I've been looking into a few of our flaky tests and come up with a couple of actions, I will comment on them individually. Co-authored-by: Elastic Machine --- packages/kbn-test/src/kbn_client/kbn_client_version.ts | 7 +++++++ .../cypress/tasks/entity_analytics.ts | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/kbn-test/src/kbn_client/kbn_client_version.ts b/packages/kbn-test/src/kbn_client/kbn_client_version.ts index a52e04a8ebd5d..710f627927260 100644 --- a/packages/kbn-test/src/kbn_client/kbn_client_version.ts +++ b/packages/kbn-test/src/kbn_client/kbn_client_version.ts @@ -19,6 +19,13 @@ export class KbnClientVersion { } const status = await this.status.get(); + + if (!status.version) { + throw new Error( + `Unable to get version from Kibana, invalid response from server: ${JSON.stringify(status)}` + ); + } + this.versionCache = status.version.number + (status.version.build_snapshot ? '-SNAPSHOT' : ''); return this.versionCache; } diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts b/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts index 5d84c28100fee..33599c47ccb5d 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts @@ -31,7 +31,8 @@ import { REFRESH_BUTTON } from '../screens/security_header'; export const updateDashboardTimeRange = () => { // eslint-disable-next-line cypress/no-force cy.get(GET_DATE_PICKER_APPLY_BUTTON(GLOBAL_FILTERS_CONTAINER)).click({ force: true }); // Force to fix global timerange flakiness - cy.get(REFRESH_BUTTON).click(); + // eslint-disable-next-line cypress/no-force + cy.get(REFRESH_BUTTON).click({ force: true }); // Force to fix even more global timerange flakiness cy.get(REFRESH_BUTTON).should('not.have.attr', 'aria-label', 'Needs updating'); }; From 5b4f4afb44142049e9de2d02887d299663a88e61 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Thu, 5 Sep 2024 10:59:35 +0200 Subject: [PATCH 21/99] [AI Assistant] Prevent Ai Assistant nav control load for any page (#192066) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📓 Summary Closes #191601 The AI Assistant nav control is currently loaded only for Observability pages. However, during its registration step in the `observabilityAIAssistantApp`, the whole async chunk leaked into any page even when unnecessary since the control was not shown. The cause was a visibility condition applied too late in the react rendering process. Lifting the control condition higher in the tree prevents the whole chunk from being loaded for any page, but only for those enabled in observability. This refactor const of a total **~93%** reduction in the impact of the AI Assistant code for pages that won't need it. Also, even if the bundle file was not excessively big, this refactor brings a nice **~33%** on the initial `observabilityAiAssistantApp.plugin.js` bundle file. | **AIAssistantApp impact on Kibana** | |--------| | **Before** Screenshot 2024-09-04 at 11 25 40 | | **After** Screenshot 2024-09-04 at 11 29 11 | **Demo** 🎥 https://github.com/user-attachments/assets/5faa4c77-52c5-40e8-8d39-78952504fede --------- Co-authored-by: Marco Antonio Ghiani Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../public/components/nav_control/index.tsx | 36 ++++++++++++++---- .../nav_control/lazy_nav_control.tsx | 38 +++++++++++++++++-- .../public/hooks/is_nav_control_visible.tsx | 21 +++++----- .../public/plugin.tsx | 12 ++---- .../tsconfig.json | 1 + 5 files changed, 77 insertions(+), 31 deletions(-) diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/index.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/index.tsx index b70d5dbade35b..66a66ecc07dc0 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/index.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/index.tsx @@ -11,14 +11,40 @@ import { css } from '@emotion/react'; import { v4 } from 'uuid'; import useObservable from 'react-use/lib/useObservable'; import { i18n } from '@kbn/i18n'; +import { CoreStart } from '@kbn/core-lifecycle-browser'; import { useObservabilityAIAssistantAppService } from '../../hooks/use_observability_ai_assistant_app_service'; import { ChatFlyout } from '../chat/chat_flyout'; import { useKibana } from '../../hooks/use_kibana'; -import { useIsNavControlVisible } from '../../hooks/is_nav_control_visible'; import { useTheme } from '../../hooks/use_theme'; import { useNavControlScreenContext } from '../../hooks/use_nav_control_screen_context'; +import { SharedProviders } from '../../utils/shared_providers'; +import { ObservabilityAIAssistantAppService } from '../../service/create_app_service'; +import { ObservabilityAIAssistantAppPluginStartDependencies } from '../../types'; + +interface NavControlWithProviderDeps { + appService: ObservabilityAIAssistantAppService; + coreStart: CoreStart; + pluginsStart: ObservabilityAIAssistantAppPluginStartDependencies; +} + +export const NavControlWithProvider = ({ + appService, + coreStart, + pluginsStart, +}: NavControlWithProviderDeps) => { + return ( + + + + ); +}; -export function NavControl({}: {}) { +export function NavControl() { const service = useObservabilityAIAssistantAppService(); const { @@ -63,8 +89,6 @@ export function NavControl({}: {}) { const keyRef = useRef(v4()); - const { isVisible } = useIsNavControlVisible(); - useEffect(() => { const conversationSubscription = service.conversations.predefinedConversation$.subscribe(() => { keyRef.current = v4(); @@ -108,10 +132,6 @@ export function NavControl({}: {}) { }; }, [service.conversations]); - if (!isVisible) { - return null; - } - return ( <> diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/lazy_nav_control.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/lazy_nav_control.tsx index 77086a9bf73aa..bed86909af417 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/lazy_nav_control.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/lazy_nav_control.tsx @@ -5,9 +5,39 @@ * 2.0. */ -import { withSuspense } from '@kbn/shared-ux-utility'; -import { lazy } from 'react'; +import { dynamic } from '@kbn/shared-ux-utility'; +import React from 'react'; +import { CoreStart } from '@kbn/core-lifecycle-browser'; +import { useIsNavControlVisible } from '../../hooks/is_nav_control_visible'; +import { ObservabilityAIAssistantAppService } from '../../service/create_app_service'; +import { ObservabilityAIAssistantAppPluginStartDependencies } from '../../types'; -export const LazyNavControl = withSuspense( - lazy(() => import('.').then((m) => ({ default: m.NavControl }))) +const LazyNavControlWithProvider = dynamic(() => + import('.').then((m) => ({ default: m.NavControlWithProvider })) ); + +interface NavControlInitiatorProps { + appService: ObservabilityAIAssistantAppService; + coreStart: CoreStart; + pluginsStart: ObservabilityAIAssistantAppPluginStartDependencies; +} + +export const NavControlInitiator = ({ + appService, + coreStart, + pluginsStart, +}: NavControlInitiatorProps) => { + const { isVisible } = useIsNavControlVisible({ coreStart, pluginsStart }); + + if (!isVisible) { + return null; + } + + return ( + + ); +}; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/hooks/is_nav_control_visible.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/hooks/is_nav_control_visible.tsx index c8386991eebbf..f82de790e05c2 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/hooks/is_nav_control_visible.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/hooks/is_nav_control_visible.tsx @@ -7,9 +7,14 @@ import { useEffect, useState } from 'react'; import { combineLatest } from 'rxjs'; -import { DEFAULT_APP_CATEGORIES, type PublicAppInfo } from '@kbn/core/public'; +import { CoreStart, DEFAULT_APP_CATEGORIES, type PublicAppInfo } from '@kbn/core/public'; import { AIAssistantType } from '@kbn/ai-assistant-management-plugin/public'; -import { useKibana } from './use_kibana'; +import { ObservabilityAIAssistantAppPluginStartDependencies } from '../types'; + +interface UseIsNavControlVisibleProps { + coreStart: CoreStart; + pluginsStart: ObservabilityAIAssistantAppPluginStartDependencies; +} function getVisibility( appId: string | undefined, @@ -30,17 +35,11 @@ function getVisibility( return categoryId === DEFAULT_APP_CATEGORIES.observability.id; } -export function useIsNavControlVisible() { +export function useIsNavControlVisible({ coreStart, pluginsStart }: UseIsNavControlVisibleProps) { const [isVisible, setIsVisible] = useState(false); - const { - services: { - application: { currentAppId$, applications$ }, - plugins: { - start: { aiAssistantManagementSelection }, - }, - }, - } = useKibana(); + const { currentAppId$, applications$ } = coreStart.application; + const { aiAssistantManagementSelection } = pluginsStart; useEffect(() => { const appSubscription = combineLatest([ diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/plugin.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/plugin.tsx index 466cde6747990..9817cc65362d6 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/plugin.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/plugin.tsx @@ -24,9 +24,8 @@ import type { ObservabilityAIAssistantAppPublicStart, } from './types'; import { createAppService, ObservabilityAIAssistantAppService } from './service/create_app_service'; -import { SharedProviders } from './utils/shared_providers'; -import { LazyNavControl } from './components/nav_control/lazy_nav_control'; import { getObsAIAssistantConnectorType } from './rule_connector'; +import { NavControlInitiator } from './components/nav_control/lazy_nav_control'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ConfigSchema {} @@ -108,14 +107,11 @@ export class ObservabilityAIAssistantAppPlugin coreStart.chrome.navControls.registerRight({ mount: (element) => { ReactDOM.render( - - - , + />, element, () => {} ); diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/tsconfig.json b/x-pack/plugins/observability_solution/observability_ai_assistant_app/tsconfig.json index bc92d37d3cd70..55d965c9c37e3 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/tsconfig.json @@ -71,6 +71,7 @@ "@kbn/observability-plugin", "@kbn/esql-datagrid", "@kbn/alerting-comparators", + "@kbn/core-lifecycle-browser", "@kbn/inference-plugin" ], "exclude": ["target/**/*"] From 69665cecd06b4a094a73257c13e67553ad678832 Mon Sep 17 00:00:00 2001 From: Tre Date: Thu, 5 Sep 2024 10:00:55 +0100 Subject: [PATCH 22/99] [FTR] Refactor test/common/services/* -> packages/kbn-ftr-common-functional-[ui-]services/* (#191805) ## Summary Moving common services to respective new homes. This PR is revived from a previously [merged](https://github.com/elastic/kibana/commit/09a365850e18822b4474fac1a1c033ab6da511a8) and [reverted PR](https://github.com/elastic/kibana/pull/191765) as [detailed here](https://github.com/elastic/kibana/pull/189051#issuecomment-2318999361). - This was due to "extra" tests being applied to https://github.com/elastic/kibana/pull/191708 - These "extra" tests were applied as https://github.com/elastic/kibana/pull/191708 changes files within `x-pack/plugins/observability_solution/` as configured [here](https://github.com/elastic/kibana/blob/main/.buildkite/scripts/pipelines/pull_request/pipeline.ts#L129) ### Why these failures were not caught in the original [PR](https://github.com/elastic/kibana/pull/189051) The pipeline is generated at runtime, and the original [PR](https://github.com/elastic/kibana/pull/189051) had zero changes under `x-pack/plugins/observability_solution/` ## Changes on top of original PR - Add `ci:all-cypress-suites` label to run extra tests - Add `services` stanza to which contains the missing references by spreading the services from `@kbn/ftr-common-functional-services` && `@kbn/ftr-common-functional-ui-services` into the stanza, for the following: - `x-pack/plugins/observability_solution/synthetics/e2e/config.ts` - `x-pack/plugins/observability_solution/apm/ftr_e2e/ftr_config.ts` - `x-pack/plugins/observability_solution/observability_onboarding/e2e/ftr_config.ts` - `x-pack/plugins/observability_solution/profiling/e2e/ftr_config.ts` - `x-pack/plugins/observability_solution/synthetics/e2e/config.ts` - `x-pack/plugins/observability_solution/uptime/e2e/config.ts` Blocked by: https://github.com/elastic/kibana/issues/191961 Resolves: https://github.com/elastic/kibana/issues/188541 --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine --- .../development-functional-tests.asciidoc | 10 ++-- .../index.ts | 9 ++++ .../services/all.ts | 14 +++++ .../services/bsearch.ts | 3 +- .../services/console.ts | 4 +- .../services/deployment.ts | 2 +- .../services/es_delete_all_indices.ts | 2 +- .../services/index_patterns.ts | 7 +-- .../services/randomness.ts | 2 +- .../services/saved_object_info/index.ts | 0 .../saved_object_info/saved_object_info.ts | 2 +- .../saved_objects_info_svc.md | 0 .../services/saved_object_info/use_with_jq.md | 0 .../services/saved_object_info/utils.ts | 0 .../tsconfig.json | 7 +++ .../index.ts | 1 + .../services/all.ts | 2 + .../services/ftr_provider_context.ts | 8 ++- .../services/security/index.ts | 2 +- .../services/security/role.ts | 0 .../services/security/role_mappings.ts | 0 .../services/security/security.ts | 2 +- .../services/security/system_indices_user.ts | 2 +- .../services/security/test_user.ts | 5 +- .../services/security/user.ts | 0 scripts/saved_objs_info.js | 2 +- test/analytics/services/index.ts | 7 ++- .../apis/console/autocomplete_entities.ts | 46 +++++++---------- test/api_integration/services/index.ts | 7 +-- test/common/config.js | 2 - test/common/ftr_provider_context.ts | 14 ----- test/common/services/console.ts | 15 ------ test/common/services/index.ts | 43 +++++++++------- .../apps/discover/ftr_provider_context.d.ts | 8 ++- test/functional/services/index.ts | 4 +- test/health_gateway/services/index.ts | 6 ++- test/server_integration/config.base.js | 4 +- test/server_integration/services/types.d.ts | 9 +++- test/tsconfig.json | 3 -- .../apm/ftr_e2e/ftr_config.ts | 7 +++ .../apm/ftr_e2e/tsconfig.json | 4 +- .../e2e/ftr_config.ts | 7 +++ .../e2e/tsconfig.json | 4 +- .../profiling/e2e/ftr_config.ts | 7 +++ .../profiling/e2e/tsconfig.json | 4 +- .../synthetics/e2e/config.ts | 7 +++ .../synthetics/e2e/tsconfig.json | 3 +- .../uptime/e2e/config.ts | 7 +++ .../uptime/e2e/tsconfig.json | 3 +- .../apis/cloud_security_posture/helper.ts | 2 +- .../apis/telemetry/telemetry.ts | 2 +- x-pack/test/common/services/bsearch_secure.ts | 4 +- x-pack/test/common/services/index.ts | 6 ++- .../fleet_api_integration/apis/test_users.ts | 2 +- x-pack/test/fleet_cypress/config.ts | 1 - .../cli_config.ts | 8 +++ x-pack/test/osquery_cypress/services.ts | 8 ++- .../helpers/create_or_update_user.ts | 2 +- .../common/create_profiling_users/index.ts | 2 +- .../test/saved_objects_field_count/config.ts | 5 ++ .../security_solution_serverless_utils.ts | 2 +- .../config/services/types.ts | 2 +- .../entity_analytics/utils/users_and_roles.ts | 2 +- .../tests/host_details.ts | 2 +- .../tests/hosts.ts | 2 +- .../tests/uncommon_processes.ts | 2 +- .../tests/network_details.ts | 2 +- .../tests/network_dns.ts | 2 +- .../tests/network_top_n_flow.ts | 2 +- .../trial_license_complete_tier/tests/tls.ts | 3 +- .../tests/overview_host.ts | 2 +- .../tests/overview_network.ts | 2 +- .../tests/authentications.ts | 2 +- .../tests/users.ts | 3 +- .../tests/events.ts | 3 +- .../tests/timeline_details.ts | 3 +- .../tsconfig.json | 2 +- .../threat_intelligence_cypress/config.ts | 5 +- .../upgrade_assistant_integration/config.js | 7 ++- .../common/console/autocomplete_entities.ts | 51 ++++++------------- .../shared/services/bsearch_secure.ts | 4 +- 81 files changed, 264 insertions(+), 190 deletions(-) rename {test/common => packages/kbn-ftr-common-functional-services}/services/bsearch.ts (98%) rename test/api_integration/apis/console/helpers.ts => packages/kbn-ftr-common-functional-services/services/console.ts (95%) rename {test/common => packages/kbn-ftr-common-functional-services}/services/deployment.ts (96%) rename {test/common => packages/kbn-ftr-common-functional-services}/services/es_delete_all_indices.ts (97%) rename {test/common => packages/kbn-ftr-common-functional-services}/services/index_patterns.ts (91%) rename {test/common => packages/kbn-ftr-common-functional-services}/services/randomness.ts (97%) rename {test/common => packages/kbn-ftr-common-functional-services}/services/saved_object_info/index.ts (100%) rename {test/common => packages/kbn-ftr-common-functional-services}/services/saved_object_info/saved_object_info.ts (97%) rename {test/common => packages/kbn-ftr-common-functional-services}/services/saved_object_info/saved_objects_info_svc.md (100%) rename {test/common => packages/kbn-ftr-common-functional-services}/services/saved_object_info/use_with_jq.md (100%) rename {test/common => packages/kbn-ftr-common-functional-services}/services/saved_object_info/utils.ts (100%) rename {test/common => packages/kbn-ftr-common-functional-ui-services}/services/security/index.ts (83%) rename {test/common => packages/kbn-ftr-common-functional-ui-services}/services/security/role.ts (100%) rename {test/common => packages/kbn-ftr-common-functional-ui-services}/services/security/role_mappings.ts (100%) rename {test/common => packages/kbn-ftr-common-functional-ui-services}/services/security/security.ts (95%) rename {test/common => packages/kbn-ftr-common-functional-ui-services}/services/security/system_indices_user.ts (97%) rename {test/common => packages/kbn-ftr-common-functional-ui-services}/services/security/test_user.ts (96%) rename {test/common => packages/kbn-ftr-common-functional-ui-services}/services/security/user.ts (100%) delete mode 100644 test/common/ftr_provider_context.ts delete mode 100644 test/common/services/console.ts diff --git a/docs/developer/contributing/development-functional-tests.asciidoc b/docs/developer/contributing/development-functional-tests.asciidoc index 23d43480eb090..88163ebb6804b 100644 --- a/docs/developer/contributing/development-functional-tests.asciidoc +++ b/docs/developer/contributing/development-functional-tests.asciidoc @@ -203,7 +203,7 @@ Tests should run at the positive security boundary condition, meaning that they The functional UI tests now default to logging in with a user named `test_user` and the roles of this user can be changed dynamically without logging in and out. -In order to achieve this a new service was introduced called `createTestUserService` (see `test/common/services/security/test_user.ts`). The purpose of this test user service is to create roles defined in the test config files and setRoles() or restoreDefaults(). +In order to achieve this a new service was introduced called `createTestUserService` (see `packages/kbn-ftr-common-functional-ui-services/services/security/test_user.ts`). The purpose of this test user service is to create roles defined in the test config files and setRoles() or restoreDefaults(). An example of how to set the role like how its defined below: @@ -366,14 +366,14 @@ await testSubjects.click(‘containerButton’); ** `find.allByCssSelector()` **retry:**::: -// * Source: {kibana-blob}test/common/services/retry/retry.ts[test/common/services/retry/retry.ts] +// * Source: {kibana-blob}packages/kbn-ftr-common-functional-services/services/retry/retry.ts[packages/kbn-ftr-common-functional-services/services/retry/retry.ts] * Helpers for retrying operations * Popular methods: ** `retry.try(fn, onFailureBlock)` - Execute `fn` in a loop until it succeeds or the default timeout elapses. The optional `onFailureBlock` is executed before each retry attempt. ** `retry.tryForTime(ms, fn, onFailureBlock)` - Execute `fn` in a loop until it succeeds or `ms` milliseconds elapses. The optional `onFailureBlock` is executed before each retry attempt. **kibanaServer:**::: -// * Source: {kibana-blob}test/common/services/kibana_server/kibana_server.js[test/common/services/kibana_server/kibana_server.js] +// * Source: {kibana-blob}packages/kbn-ftr-common-functional-services/services/kibana_server/kibana_server.ts[packages/kbn-ftr-common-functional-services/services/kibana_server/kibana_server.ts] * Helpers for interacting with {kib}'s server * Commonly used methods: ** `kibanaServer.uiSettings.update()` @@ -381,7 +381,7 @@ await testSubjects.click(‘containerButton’); ** `kibanaServer.status.getOverallState()` **esArchiver:**::: -// * Source: {kibana-blob}test/common/services/es_archiver.ts[test/common/services/es_archiver.ts] +// * Source: {kibana-blob}packages/kbn-ftr-common-functional-services/services/es_archiver.ts[packages/kbn-ftr-common-functional-services/services/es_archiver.ts] * Load/unload archives created with the `esArchiver` * Popular methods: ** `esArchiver.load(path)` @@ -393,7 +393,7 @@ Full list of services that are used in functional tests can be found here: {kiba **Low-level utilities:**::: * es -// ** Source: {kibana-blob}test/common/services/es.ts[test/common/services/es.ts] +// ** Source: {kibana-blob}packages/kbn-ftr-common-functional-services/services/es.ts[packages/kbn-ftr-common-functional-services/services/es.ts] ** {es} client ** Higher level options: `kibanaServer.uiSettings` or `esArchiver` * remote diff --git a/packages/kbn-ftr-common-functional-services/index.ts b/packages/kbn-ftr-common-functional-services/index.ts index 3cc6df44adf01..36d76c7e2ffd7 100644 --- a/packages/kbn-ftr-common-functional-services/index.ts +++ b/packages/kbn-ftr-common-functional-services/index.ts @@ -10,6 +10,7 @@ import { ProvidedType } from '@kbn/test'; export { services as commonFunctionalServices } from './services/all'; import { KibanaServerProvider } from './services/kibana_server'; +export { KibanaServerProvider } from './services/kibana_server'; export type KibanaServer = ProvidedType; export { RetryService } from './services/retry'; @@ -18,6 +19,7 @@ import { EsArchiverProvider } from './services/es_archiver'; export type EsArchiver = ProvidedType; import { EsProvider } from './services/es'; +export { EsProvider } from './services/es'; export type Es = ProvidedType; import { SupertestWithoutAuthProvider } from './services/supertest_without_auth'; @@ -29,3 +31,10 @@ import { SamlAuthProvider } from './services/saml_auth/saml_auth_provider'; export type SamlAuthProviderType = ProvidedType; export type { FtrProviderContext } from './services/ftr_provider_context'; +export { runSavedObjInfoSvc } from './services/saved_object_info'; + +export type { BsearchService, SendOptions } from './services/bsearch'; +export { SavedObjectInfoService } from './services/saved_object_info'; +export { DeploymentService } from './services/deployment'; +export { IndexPatternsService } from './services/index_patterns'; +export { RandomnessService } from './services/randomness'; diff --git a/packages/kbn-ftr-common-functional-services/services/all.ts b/packages/kbn-ftr-common-functional-services/services/all.ts index 49308faeb3dd0..c6c0fb792bb81 100644 --- a/packages/kbn-ftr-common-functional-services/services/all.ts +++ b/packages/kbn-ftr-common-functional-services/services/all.ts @@ -10,6 +10,13 @@ import { EsArchiverProvider } from './es_archiver'; import { EsProvider } from './es'; import { KibanaServerProvider } from './kibana_server'; import { RetryService } from './retry'; +import { BsearchService } from './bsearch'; +import { ConsoleProvider } from './console'; +import { DeploymentService } from './deployment'; +import { EsDeleteAllIndicesProvider } from './es_delete_all_indices'; +import { IndexPatternsService } from './index_patterns'; +import { SavedObjectInfoService } from './saved_object_info'; +import { RandomnessService } from './randomness'; import { SupertestWithoutAuthProvider } from './supertest_without_auth'; import { SamlAuthProvider } from './saml_auth'; @@ -18,6 +25,13 @@ export const services = { kibanaServer: KibanaServerProvider, esArchiver: EsArchiverProvider, retry: RetryService, + bsearch: BsearchService, + console: ConsoleProvider, + deployment: DeploymentService, + esDeleteAllIndices: EsDeleteAllIndicesProvider, + indexPatterns: IndexPatternsService, + savedObjectInfo: SavedObjectInfoService, + randomness: RandomnessService, supertestWithoutAuth: SupertestWithoutAuthProvider, samlAuth: SamlAuthProvider, }; diff --git a/test/common/services/bsearch.ts b/packages/kbn-ftr-common-functional-services/services/bsearch.ts similarity index 98% rename from test/common/services/bsearch.ts rename to packages/kbn-ftr-common-functional-services/services/bsearch.ts index 81063813cec5f..b36834dedbca5 100644 --- a/test/common/services/bsearch.ts +++ b/packages/kbn-ftr-common-functional-services/services/bsearch.ts @@ -12,7 +12,7 @@ import type SuperTest from 'supertest'; import type { IEsSearchResponse } from '@kbn/search-types'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { BFETCH_ROUTE_VERSION_LATEST } from '@kbn/bfetch-plugin/common'; -import { FtrService } from '../ftr_provider_context'; +import { FtrService } from './ftr_provider_context'; /** * Function copied from here: @@ -62,6 +62,7 @@ export interface SendOptions { * }); * expect(response).eql({ ... your value ... }); */ + export class BsearchService extends FtrService { private readonly retry = this.ctx.getService('retry'); diff --git a/test/api_integration/apis/console/helpers.ts b/packages/kbn-ftr-common-functional-services/services/console.ts similarity index 95% rename from test/api_integration/apis/console/helpers.ts rename to packages/kbn-ftr-common-functional-services/services/console.ts index cfd1365f212fa..1ca5128d83f7c 100644 --- a/test/api_integration/apis/console/helpers.ts +++ b/packages/kbn-ftr-common-functional-services/services/console.ts @@ -6,9 +6,9 @@ * Side Public License, v 1. */ -import type { FtrProviderContext } from '../../ftr_provider_context'; +import type { FtrProviderContext } from './ftr_provider_context'; -export function helpers(getService: FtrProviderContext['getService']) { +export function ConsoleProvider({ getService }: FtrProviderContext) { const client = getService('es'); const createIndex = async (indexName: string) => { diff --git a/test/common/services/deployment.ts b/packages/kbn-ftr-common-functional-services/services/deployment.ts similarity index 96% rename from test/common/services/deployment.ts rename to packages/kbn-ftr-common-functional-services/services/deployment.ts index e61d6b360da19..28474a6bc60e2 100644 --- a/test/common/services/deployment.ts +++ b/packages/kbn-ftr-common-functional-services/services/deployment.ts @@ -11,7 +11,7 @@ import { Agent } from 'https'; import fetch from 'node-fetch'; import { getUrl } from '@kbn/test'; -import { FtrService } from '../ftr_provider_context'; +import { FtrService } from './ftr_provider_context'; export class DeploymentService extends FtrService { private readonly config = this.ctx.getService('config'); diff --git a/test/common/services/es_delete_all_indices.ts b/packages/kbn-ftr-common-functional-services/services/es_delete_all_indices.ts similarity index 97% rename from test/common/services/es_delete_all_indices.ts rename to packages/kbn-ftr-common-functional-services/services/es_delete_all_indices.ts index 5f0ecba2cbde8..cf3f93d9ef6aa 100644 --- a/test/common/services/es_delete_all_indices.ts +++ b/packages/kbn-ftr-common-functional-services/services/es_delete_all_indices.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from './ftr_provider_context'; export function EsDeleteAllIndicesProvider({ getService }: FtrProviderContext) { const log = getService('log'); diff --git a/test/common/services/index_patterns.ts b/packages/kbn-ftr-common-functional-services/services/index_patterns.ts similarity index 91% rename from test/common/services/index_patterns.ts rename to packages/kbn-ftr-common-functional-services/services/index_patterns.ts index 3fe02863b8568..6113040b927b3 100644 --- a/test/common/services/index_patterns.ts +++ b/packages/kbn-ftr-common-functional-services/services/index_patterns.ts @@ -6,10 +6,11 @@ * Side Public License, v 1. */ -import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import type { DataViewSpec } from '@kbn/data-plugin/common'; + import { INITIAL_REST_VERSION } from '@kbn/data-views-plugin/server/constants'; -import { DataViewSpec } from '@kbn/data-plugin/common'; -import { FtrService } from '../ftr_provider_context'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import { FtrService } from './ftr_provider_context'; export class IndexPatternsService extends FtrService { private readonly kibanaServer = this.ctx.getService('kibanaServer'); diff --git a/test/common/services/randomness.ts b/packages/kbn-ftr-common-functional-services/services/randomness.ts similarity index 97% rename from test/common/services/randomness.ts rename to packages/kbn-ftr-common-functional-services/services/randomness.ts index c799c34539f15..d3ea0c74ff5de 100644 --- a/test/common/services/randomness.ts +++ b/packages/kbn-ftr-common-functional-services/services/randomness.ts @@ -9,7 +9,7 @@ import Chance from 'chance'; import { ToolingLog } from '@kbn/tooling-log'; -import { FtrService } from '../ftr_provider_context'; +import { FtrService } from './ftr_provider_context'; let __CACHED_SEED__: number | undefined; function getSeed(log: ToolingLog) { diff --git a/test/common/services/saved_object_info/index.ts b/packages/kbn-ftr-common-functional-services/services/saved_object_info/index.ts similarity index 100% rename from test/common/services/saved_object_info/index.ts rename to packages/kbn-ftr-common-functional-services/services/saved_object_info/index.ts diff --git a/test/common/services/saved_object_info/saved_object_info.ts b/packages/kbn-ftr-common-functional-services/services/saved_object_info/saved_object_info.ts similarity index 97% rename from test/common/services/saved_object_info/saved_object_info.ts rename to packages/kbn-ftr-common-functional-services/services/saved_object_info/saved_object_info.ts index a1b98cbd408bf..289c730cac17a 100644 --- a/test/common/services/saved_object_info/saved_object_info.ts +++ b/packages/kbn-ftr-common-functional-services/services/saved_object_info/saved_object_info.ts @@ -13,7 +13,7 @@ import { flow, pipe } from 'fp-ts/function'; import * as TE from 'fp-ts/lib/TaskEither'; import * as T from 'fp-ts/lib/Task'; import { ToolingLog } from '@kbn/tooling-log'; -import { FtrService } from '../../ftr_provider_context'; +import { FtrService } from '../ftr_provider_context'; import { print } from './utils'; const pluck = diff --git a/test/common/services/saved_object_info/saved_objects_info_svc.md b/packages/kbn-ftr-common-functional-services/services/saved_object_info/saved_objects_info_svc.md similarity index 100% rename from test/common/services/saved_object_info/saved_objects_info_svc.md rename to packages/kbn-ftr-common-functional-services/services/saved_object_info/saved_objects_info_svc.md diff --git a/test/common/services/saved_object_info/use_with_jq.md b/packages/kbn-ftr-common-functional-services/services/saved_object_info/use_with_jq.md similarity index 100% rename from test/common/services/saved_object_info/use_with_jq.md rename to packages/kbn-ftr-common-functional-services/services/saved_object_info/use_with_jq.md diff --git a/test/common/services/saved_object_info/utils.ts b/packages/kbn-ftr-common-functional-services/services/saved_object_info/utils.ts similarity index 100% rename from test/common/services/saved_object_info/utils.ts rename to packages/kbn-ftr-common-functional-services/services/saved_object_info/utils.ts diff --git a/packages/kbn-ftr-common-functional-services/tsconfig.json b/packages/kbn-ftr-common-functional-services/tsconfig.json index 56a442ad2f5a9..490eed5f7ac0e 100644 --- a/packages/kbn-ftr-common-functional-services/tsconfig.json +++ b/packages/kbn-ftr-common-functional-services/tsconfig.json @@ -16,8 +16,15 @@ "@kbn/es-archiver", "@kbn/test", "@kbn/expect", + "@kbn/search-types", + "@kbn/core-http-common", + "@kbn/bfetch-plugin", + "@kbn/data-plugin", + "@kbn/dev-cli-runner", + "@kbn/dev-cli-errors", "@kbn/repo-info", "@kbn/es", + "@kbn/data-views-plugin" ], "exclude": [ "target/**/*", diff --git a/packages/kbn-ftr-common-functional-ui-services/index.ts b/packages/kbn-ftr-common-functional-ui-services/index.ts index cd383a03e5f5d..f5f5b9df5b8ae 100644 --- a/packages/kbn-ftr-common-functional-ui-services/index.ts +++ b/packages/kbn-ftr-common-functional-ui-services/index.ts @@ -22,3 +22,4 @@ export { } from './services/remote/network_profiles'; export type { TimeoutOpt } from './types'; export { TestSubjects } from './services/test_subjects'; +export { SecurityService } from './services/security'; 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 bffa7468e14ea..610697c69dfbf 100644 --- a/packages/kbn-ftr-common-functional-ui-services/services/all.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/all.ts @@ -12,6 +12,7 @@ import { FindProvider } from './find'; import { TestSubjects } from './test_subjects'; import { BrowserProvider } from './browser'; import { ToastsService } from './toasts'; +import { SecurityServiceProvider } from './security'; export const services = { retryOnStale: RetryOnStaleProvider, @@ -20,4 +21,5 @@ export const services = { testSubjects: TestSubjects, browser: BrowserProvider, toasts: ToastsService, + security: SecurityServiceProvider, }; 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 992fe27059e45..6f589ac6d1bb4 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,12 +7,18 @@ */ import { GenericFtrProviderContext, GenericFtrService } from '@kbn/test'; -import { RetryService } from '@kbn/ftr-common-functional-services'; +import { + RetryService, + EsProvider, + KibanaServerProvider, +} from '@kbn/ftr-common-functional-services'; import { services as commonFunctionalUiServices } from './all'; const services = { ...commonFunctionalUiServices, retry: RetryService, + es: EsProvider, + kibanaServer: KibanaServerProvider, }; export type FtrProviderContext = GenericFtrProviderContext; diff --git a/test/common/services/security/index.ts b/packages/kbn-ftr-common-functional-ui-services/services/security/index.ts similarity index 83% rename from test/common/services/security/index.ts rename to packages/kbn-ftr-common-functional-ui-services/services/security/index.ts index d34246c0c4411..308b2f8b075a0 100644 --- a/test/common/services/security/index.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/security/index.ts @@ -6,4 +6,4 @@ * Side Public License, v 1. */ -export { SecurityServiceProvider } from './security'; +export { SecurityService, SecurityServiceProvider } from './security'; diff --git a/test/common/services/security/role.ts b/packages/kbn-ftr-common-functional-ui-services/services/security/role.ts similarity index 100% rename from test/common/services/security/role.ts rename to packages/kbn-ftr-common-functional-ui-services/services/security/role.ts diff --git a/test/common/services/security/role_mappings.ts b/packages/kbn-ftr-common-functional-ui-services/services/security/role_mappings.ts similarity index 100% rename from test/common/services/security/role_mappings.ts rename to packages/kbn-ftr-common-functional-ui-services/services/security/role_mappings.ts diff --git a/test/common/services/security/security.ts b/packages/kbn-ftr-common-functional-ui-services/services/security/security.ts similarity index 95% rename from test/common/services/security/security.ts rename to packages/kbn-ftr-common-functional-ui-services/services/security/security.ts index a182f225f2388..5a5ff531acd5e 100644 --- a/test/common/services/security/security.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/security/security.ts @@ -9,7 +9,7 @@ import { Role } from './role'; import { User } from './user'; import { RoleMappings } from './role_mappings'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../ftr_provider_context'; import { createTestUserService, TestUserSupertestProvider, TestUser } from './test_user'; import { createSystemIndicesUser } from './system_indices_user'; diff --git a/test/common/services/security/system_indices_user.ts b/packages/kbn-ftr-common-functional-ui-services/services/security/system_indices_user.ts similarity index 97% rename from test/common/services/security/system_indices_user.ts rename to packages/kbn-ftr-common-functional-ui-services/services/security/system_indices_user.ts index 52e166c645093..9d6016ebb17e9 100644 --- a/test/common/services/security/system_indices_user.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/security/system_indices_user.ts @@ -13,7 +13,7 @@ import { createEsClientForFtrConfig, createRemoteEsClientForFtrConfig, } from '@kbn/test'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../ftr_provider_context'; const SYSTEM_INDICES_SUPERUSER_ROLE = 'system_indices_superuser'; diff --git a/test/common/services/security/test_user.ts b/packages/kbn-ftr-common-functional-ui-services/services/security/test_user.ts similarity index 96% rename from test/common/services/security/test_user.ts rename to packages/kbn-ftr-common-functional-ui-services/services/security/test_user.ts index f3012304a95bd..10a6da9f707dd 100644 --- a/test/common/services/security/test_user.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/security/test_user.ts @@ -9,10 +9,11 @@ import { format as formatUrl } from 'url'; import supertest from 'supertest'; -import { type Browser, TestSubjects } from '@kbn/ftr-common-functional-ui-services'; +import type { Browser } from '../browser'; +import type { TestSubjects } from '../test_subjects'; import { Role } from './role'; import { User } from './user'; -import { FtrService, FtrProviderContext } from '../../ftr_provider_context'; +import { FtrService, FtrProviderContext } from '../ftr_provider_context'; const TEST_USER_NAME = 'test_user'; const TEST_USER_PASSWORD = 'changeme'; diff --git a/test/common/services/security/user.ts b/packages/kbn-ftr-common-functional-ui-services/services/security/user.ts similarity index 100% rename from test/common/services/security/user.ts rename to packages/kbn-ftr-common-functional-ui-services/services/security/user.ts diff --git a/scripts/saved_objs_info.js b/scripts/saved_objs_info.js index f17a2897b83da..229565921ba90 100644 --- a/scripts/saved_objs_info.js +++ b/scripts/saved_objs_info.js @@ -7,4 +7,4 @@ */ require('../src/setup_node_env'); -require('@kbn/test-suites-src/common/services/saved_object_info').runSavedObjInfoSvc(); +require('@kbn/ftr-common-functional-services').runSavedObjInfoSvc(); diff --git a/test/analytics/services/index.ts b/test/analytics/services/index.ts index 0c75df9bc2050..0d3465986249a 100644 --- a/test/analytics/services/index.ts +++ b/test/analytics/services/index.ts @@ -7,14 +7,17 @@ */ import { GenericFtrProviderContext } from '@kbn/test'; -import { services as commonServices } from '../../common/services'; +import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; +import { commonFunctionalUIServices } from '@kbn/ftr-common-functional-ui-services'; + import { services as functionalServices } from '../../functional/services'; import { pageObjects } from '../../functional/page_objects'; import { KibanaEBTServerProvider, KibanaEBTUIProvider } from './kibana_ebt'; export const services = { - ...commonServices, + ...commonFunctionalServices, + ...commonFunctionalUIServices, ...functionalServices, kibana_ebt_server: KibanaEBTServerProvider, kibana_ebt_ui: KibanaEBTUIProvider, diff --git a/test/api_integration/apis/console/autocomplete_entities.ts b/test/api_integration/apis/console/autocomplete_entities.ts index a410e50950cd1..1993ef1f7fe19 100644 --- a/test/api_integration/apis/console/autocomplete_entities.ts +++ b/test/api_integration/apis/console/autocomplete_entities.ts @@ -8,25 +8,11 @@ import expect from '@kbn/expect'; import type { FtrProviderContext } from '../../ftr_provider_context'; -import { helpers } from './helpers'; export default ({ getService }: FtrProviderContext) => { - const { - createIndex, - createAlias, - createLegacyTemplate, - createIndexTemplate, - createComponentTemplate, - createDataStream, - deleteIndex, - deleteAlias, - deleteLegacyTemplate, - deleteIndexTemplate, - deleteComponentTemplate, - deleteDataStream, - } = helpers(getService); - + const console = getService('console'); const supertest = getService('supertest'); + const sendRequest = (query: object) => supertest.get('/api/console/autocomplete_entities').query(query); @@ -40,22 +26,26 @@ export default ({ getService }: FtrProviderContext) => { before(async () => { // Setup indices, aliases, templates, and data streams - await createIndex(indexName); - await createAlias(indexName, aliasName); - await createComponentTemplate(componentTemplateName); - await createIndexTemplate(indexTemplateName, [dataStreamName], [componentTemplateName]); - await createDataStream(dataStreamName); - await createLegacyTemplate(legacyTemplateName); + await console.createIndex(indexName); + await console.createAlias(indexName, aliasName); + await console.createComponentTemplate(componentTemplateName); + await console.createIndexTemplate( + indexTemplateName, + [dataStreamName], + [componentTemplateName] + ); + await console.createDataStream(dataStreamName); + await console.createLegacyTemplate(legacyTemplateName); }); after(async () => { // Cleanup indices, aliases, templates, and data streams - await deleteAlias(indexName, aliasName); - await deleteIndex(indexName); - await deleteDataStream(dataStreamName); - await deleteIndexTemplate(indexTemplateName); - await deleteComponentTemplate(componentTemplateName); - await deleteLegacyTemplate(legacyTemplateName); + await console.deleteAlias(indexName, aliasName); + await console.deleteIndex(indexName); + await console.deleteDataStream(dataStreamName); + await console.deleteIndexTemplate(indexTemplateName); + await console.deleteComponentTemplate(componentTemplateName); + await console.deleteLegacyTemplate(legacyTemplateName); }); it('should not succeed if no settings are provided in query params', async () => { diff --git a/test/api_integration/services/index.ts b/test/api_integration/services/index.ts index 42a2616b781ac..f72460b7ffc5f 100644 --- a/test/api_integration/services/index.ts +++ b/test/api_integration/services/index.ts @@ -6,12 +6,13 @@ * Side Public License, v 1. */ -import { services as commonServices } from '../../common/services'; - +import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; +import { commonFunctionalUIServices } from '@kbn/ftr-common-functional-ui-services'; import { KibanaSupertestProvider, ElasticsearchSupertestProvider } from './supertest'; export const services = { - ...commonServices, + ...commonFunctionalServices, + ...commonFunctionalUIServices, supertest: KibanaSupertestProvider, esSupertest: ElasticsearchSupertestProvider, }; diff --git a/test/common/config.js b/test/common/config.js index 163703a693356..8f2d6b7e14018 100644 --- a/test/common/config.js +++ b/test/common/config.js @@ -9,7 +9,6 @@ import path from 'path'; import { format as formatUrl } from 'url'; import { esTestConfig, kbnTestConfig, kibanaServerTestUser } from '@kbn/test'; -import { services } from './services'; export default function () { const servers = { @@ -85,6 +84,5 @@ export default function () { })}`, ], }, - services, }; } diff --git a/test/common/ftr_provider_context.ts b/test/common/ftr_provider_context.ts deleted file mode 100644 index 6d21aedfe1d5e..0000000000000 --- a/test/common/ftr_provider_context.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 { GenericFtrProviderContext, GenericFtrService } from '@kbn/test'; - -import { services } from './services'; - -export type FtrProviderContext = GenericFtrProviderContext; -export class FtrService extends GenericFtrService {} diff --git a/test/common/services/console.ts b/test/common/services/console.ts deleted file mode 100644 index a864952fa081b..0000000000000 --- a/test/common/services/console.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import type { FtrProviderContext } from '../ftr_provider_context'; -import { helpers } from '../../api_integration/apis/console/helpers'; -export function ConsoleProvider({ getService }: FtrProviderContext) { - return { - helpers: helpers(getService), - }; -} diff --git a/test/common/services/index.ts b/test/common/services/index.ts index ccc786d4ccc6e..18855d9dee114 100644 --- a/test/common/services/index.ts +++ b/test/common/services/index.ts @@ -7,17 +7,26 @@ */ import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; -import { DeploymentService } from './deployment'; -import { RandomnessService } from './randomness'; -import { SecurityServiceProvider } from './security'; -import { EsDeleteAllIndicesProvider } from './es_delete_all_indices'; -import { SavedObjectInfoService } from './saved_object_info'; -import { IndexPatternsService } from './index_patterns'; -import { BsearchService } from './bsearch'; -import { ConsoleProvider } from './console'; +import { commonFunctionalUIServices } from '@kbn/ftr-common-functional-ui-services'; // pick only services that work for any FTR config, e.g. 'samlAuth' requires SAML setup in config file -const { es, esArchiver, kibanaServer, retry, supertestWithoutAuth } = commonFunctionalServices; +const { + es, + esArchiver, + kibanaServer, + retry, + supertestWithoutAuth, + deployment, + randomness, + esDeleteAllIndices, + savedObjectInfo, + indexPatterns, + bsearch, + console, +} = commonFunctionalServices; + +// pick what was there previously +const { security } = commonFunctionalUIServices; export const services = { es, @@ -25,12 +34,12 @@ export const services = { kibanaServer, retry, supertestWithoutAuth, - deployment: DeploymentService, - randomness: RandomnessService, - security: SecurityServiceProvider, - esDeleteAllIndices: EsDeleteAllIndicesProvider, - savedObjectInfo: SavedObjectInfoService, - indexPatterns: IndexPatternsService, - bsearch: BsearchService, - console: ConsoleProvider, + deployment, + randomness, + security, + esDeleteAllIndices, + savedObjectInfo, + indexPatterns, + bsearch, + console, }; diff --git a/test/functional/apps/discover/ftr_provider_context.d.ts b/test/functional/apps/discover/ftr_provider_context.d.ts index 5bf34af1bf9f3..b006a98a73d7c 100644 --- a/test/functional/apps/discover/ftr_provider_context.d.ts +++ b/test/functional/apps/discover/ftr_provider_context.d.ts @@ -7,7 +7,13 @@ */ import { GenericFtrProviderContext } from '@kbn/test'; -import { services } from '../../services'; +import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; +import { services as functionalServces } from '../../services'; import { pageObjects } from '../../page_objects'; +const services = { + ...functionalServces, + ...commonFunctionalServices, +}; + export type FtrProviderContext = GenericFtrProviderContext; diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 83672889eff75..01df9b5fdcbbf 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -7,7 +7,7 @@ */ import { commonFunctionalUIServices } from '@kbn/ftr-common-functional-ui-services'; -import { services as commonServiceProviders } from '../../common/services'; +import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; import { AppsMenuService } from './apps_menu'; import { @@ -57,7 +57,7 @@ import { ESQLService } from './esql'; import { DataViewsService } from './data_views'; export const services = { - ...commonServiceProviders, + ...commonFunctionalServices, ...commonFunctionalUIServices, filterBar: FilterBarService, queryBar: QueryBarService, diff --git a/test/health_gateway/services/index.ts b/test/health_gateway/services/index.ts index b9c44e227adae..5a89fb849f952 100644 --- a/test/health_gateway/services/index.ts +++ b/test/health_gateway/services/index.ts @@ -6,11 +6,13 @@ * Side Public License, v 1. */ -import { services as commonServices } from '../../common/services'; +import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; +import { commonFunctionalUIServices } from '@kbn/ftr-common-functional-ui-services'; import { HealthGatewayService } from './health_gateway'; export const services = { - ...commonServices, + ...commonFunctionalServices, + ...commonFunctionalUIServices, healthGateway: HealthGatewayService, }; diff --git a/test/server_integration/config.base.js b/test/server_integration/config.base.js index 71006c258c423..61243595505eb 100644 --- a/test/server_integration/config.base.js +++ b/test/server_integration/config.base.js @@ -12,13 +12,15 @@ import { ElasticsearchSupertestProvider, } from './services'; +import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; + export default async function ({ readConfigFile }) { const commonConfig = await readConfigFile(require.resolve('../common/config')); const functionalConfig = await readConfigFile(require.resolve('../functional/config.base.js')); return { services: { - ...commonConfig.get('services'), + ...commonFunctionalServices, supertest: createKibanaSupertestProvider(), supertestWithoutAuth: KibanaSupertestWithoutAuthProvider, esSupertest: ElasticsearchSupertestProvider, diff --git a/test/server_integration/services/types.d.ts b/test/server_integration/services/types.d.ts index 2df95f0297f90..204c0ae0106e5 100644 --- a/test/server_integration/services/types.d.ts +++ b/test/server_integration/services/types.d.ts @@ -7,7 +7,14 @@ */ import { GenericFtrProviderContext } from '@kbn/test'; -import { services as kibanaCommonServices } from '../../common/services'; +import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; +import { commonFunctionalUIServices } from '@kbn/ftr-common-functional-ui-services'; + +export const kibanaCommonServices = { + ...commonFunctionalServices, + ...commonFunctionalUIServices, +} as const; + import { services as kibanaApiIntegrationServices } from '../../api_integration/services'; export type FtrProviderContext = GenericFtrProviderContext< diff --git a/test/tsconfig.json b/test/tsconfig.json index 9f9f062a16492..8b0d946bded62 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -47,8 +47,6 @@ "@kbn/controls-plugin", "@kbn/field-formats-plugin", "@kbn/axe-config", - "@kbn/dev-cli-runner", - "@kbn/dev-cli-errors", "@kbn/data-view-field-editor-plugin", "@kbn/data-views-plugin", "@kbn/guided-onboarding-plugin", @@ -71,7 +69,6 @@ "@kbn/links-plugin", "@kbn/ftr-common-functional-ui-services", "@kbn/monaco", - "@kbn/search-types", "@kbn/console-plugin", "@kbn/core-chrome-browser", "@kbn/default-nav-ml", diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/ftr_config.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/ftr_config.ts index 9a0ccb56f1ad6..58cf601c33c43 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/ftr_config.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/ftr_config.ts @@ -7,6 +7,8 @@ import { FtrConfigProviderContext } from '@kbn/test'; import { CA_CERT_PATH } from '@kbn/dev-utils'; +import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; +import { commonFunctionalUIServices } from '@kbn/ftr-common-functional-ui-services'; import { cypressTestRunner } from './cypress_test_runner'; import { FtrProviderContext } from './ftr_provider_context'; @@ -21,6 +23,11 @@ async function ftrConfig({ readConfigFile }: FtrConfigProviderContext) { return { ...kibanaCommonTestsConfig.getAll(), + services: { + ...commonFunctionalServices, + ...commonFunctionalUIServices, + }, + esTestCluster: { ...xpackFunctionalTestsConfig.get('esTestCluster'), serverArgs: [ diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/tsconfig.json b/x-pack/plugins/observability_solution/apm/ftr_e2e/tsconfig.json index 6da58add924b0..804f3a3efa0a4 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/tsconfig.json +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/tsconfig.json @@ -14,6 +14,8 @@ "@kbn/dev-utils", "@kbn/axe-config", "@kbn/cypress-config", - "@kbn/apm-plugin" + "@kbn/apm-plugin", + "@kbn/ftr-common-functional-services", + "@kbn/ftr-common-functional-ui-services" ] } diff --git a/x-pack/plugins/observability_solution/observability_onboarding/e2e/ftr_config.ts b/x-pack/plugins/observability_solution/observability_onboarding/e2e/ftr_config.ts index 757382042c5e9..56cb76e2b2ac7 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/e2e/ftr_config.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/e2e/ftr_config.ts @@ -7,6 +7,8 @@ import { FtrConfigProviderContext } from '@kbn/test'; import { CA_CERT_PATH } from '@kbn/dev-utils'; +import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; +import { commonFunctionalUIServices } from '@kbn/ftr-common-functional-ui-services'; import path from 'path'; const kibanaYamlFilePath = path.join(__dirname, './ftr_kibana.yml'); @@ -22,6 +24,11 @@ async function ftrConfig({ readConfigFile }: FtrConfigProviderContext) { return { ...kibanaCommonTestsConfig.getAll(), + services: { + ...commonFunctionalServices, + ...commonFunctionalUIServices, + }, + esTestCluster: { ...xpackFunctionalTestsConfig.get('esTestCluster'), serverArgs: [ diff --git a/x-pack/plugins/observability_solution/observability_onboarding/e2e/tsconfig.json b/x-pack/plugins/observability_solution/observability_onboarding/e2e/tsconfig.json index 8970ccc1749df..94d4f2278cb63 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/e2e/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability_onboarding/e2e/tsconfig.json @@ -12,6 +12,8 @@ "@kbn/test", "@kbn/dev-utils", "@kbn/cypress-config", - "@kbn/observability-onboarding-plugin" + "@kbn/observability-onboarding-plugin", + "@kbn/ftr-common-functional-services", + "@kbn/ftr-common-functional-ui-services" ] } diff --git a/x-pack/plugins/observability_solution/profiling/e2e/ftr_config.ts b/x-pack/plugins/observability_solution/profiling/e2e/ftr_config.ts index 757382042c5e9..56cb76e2b2ac7 100644 --- a/x-pack/plugins/observability_solution/profiling/e2e/ftr_config.ts +++ b/x-pack/plugins/observability_solution/profiling/e2e/ftr_config.ts @@ -7,6 +7,8 @@ import { FtrConfigProviderContext } from '@kbn/test'; import { CA_CERT_PATH } from '@kbn/dev-utils'; +import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; +import { commonFunctionalUIServices } from '@kbn/ftr-common-functional-ui-services'; import path from 'path'; const kibanaYamlFilePath = path.join(__dirname, './ftr_kibana.yml'); @@ -22,6 +24,11 @@ async function ftrConfig({ readConfigFile }: FtrConfigProviderContext) { return { ...kibanaCommonTestsConfig.getAll(), + services: { + ...commonFunctionalServices, + ...commonFunctionalUIServices, + }, + esTestCluster: { ...xpackFunctionalTestsConfig.get('esTestCluster'), serverArgs: [ diff --git a/x-pack/plugins/observability_solution/profiling/e2e/tsconfig.json b/x-pack/plugins/observability_solution/profiling/e2e/tsconfig.json index 6e8b7e3a8d3bb..c1a5e4f90e020 100644 --- a/x-pack/plugins/observability_solution/profiling/e2e/tsconfig.json +++ b/x-pack/plugins/observability_solution/profiling/e2e/tsconfig.json @@ -12,6 +12,8 @@ "@kbn/test", "@kbn/dev-utils", "@kbn/cypress-config", - "@kbn/observability-plugin" + "@kbn/observability-plugin", + "@kbn/ftr-common-functional-services", + "@kbn/ftr-common-functional-ui-services" ] } diff --git a/x-pack/plugins/observability_solution/synthetics/e2e/config.ts b/x-pack/plugins/observability_solution/synthetics/e2e/config.ts index ea3d57ff4fca5..06088cfcdd02a 100644 --- a/x-pack/plugins/observability_solution/synthetics/e2e/config.ts +++ b/x-pack/plugins/observability_solution/synthetics/e2e/config.ts @@ -7,6 +7,8 @@ import { FtrConfigProviderContext } from '@kbn/test'; import { CA_CERT_PATH } from '@kbn/dev-utils'; +import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; +import { commonFunctionalUIServices } from '@kbn/ftr-common-functional-ui-services'; import { readKibanaConfig } from './tasks/read_kibana_config'; const MANIFEST_KEY = 'xpack.uptime.service.manifestUrl'; const SERVICE_PASSWORD = 'xpack.uptime.service.password'; @@ -29,6 +31,11 @@ async function config({ readConfigFile }: FtrConfigProviderContext) { return { ...kibanaCommonTestsConfig.getAll(), + services: { + ...commonFunctionalServices, + ...commonFunctionalUIServices, + }, + esTestCluster: { ...xpackFunctionalTestsConfig.get('esTestCluster'), serverArgs: [ diff --git a/x-pack/plugins/observability_solution/synthetics/e2e/tsconfig.json b/x-pack/plugins/observability_solution/synthetics/e2e/tsconfig.json index 6fc40dded4e72..bbc7edf10c1f6 100644 --- a/x-pack/plugins/observability_solution/synthetics/e2e/tsconfig.json +++ b/x-pack/plugins/observability_solution/synthetics/e2e/tsconfig.json @@ -15,6 +15,7 @@ "@kbn/apm-plugin", "@kbn/es-archiver", "@kbn/repo-info", - "@kbn/synthetics-plugin" + "@kbn/synthetics-plugin", + "@kbn/ftr-common-functional-ui-services" ] } diff --git a/x-pack/plugins/observability_solution/uptime/e2e/config.ts b/x-pack/plugins/observability_solution/uptime/e2e/config.ts index 18fe9bfd1712a..4f3e86eeb35ea 100644 --- a/x-pack/plugins/observability_solution/uptime/e2e/config.ts +++ b/x-pack/plugins/observability_solution/uptime/e2e/config.ts @@ -7,6 +7,8 @@ import { FtrConfigProviderContext } from '@kbn/test'; import { CA_CERT_PATH } from '@kbn/dev-utils'; +import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; +import { commonFunctionalUIServices } from '@kbn/ftr-common-functional-ui-services'; import { readKibanaConfig } from './tasks/read_kibana_config'; const MANIFEST_KEY = 'xpack.uptime.service.manifestUrl'; const SERVICE_PASSWORD = 'xpack.uptime.service.password'; @@ -29,6 +31,11 @@ async function config({ readConfigFile }: FtrConfigProviderContext) { return { ...kibanaCommonTestsConfig.getAll(), + services: { + ...commonFunctionalServices, + ...commonFunctionalUIServices, + }, + esTestCluster: { ...xpackFunctionalTestsConfig.get('esTestCluster'), serverArgs: [ diff --git a/x-pack/plugins/observability_solution/uptime/e2e/tsconfig.json b/x-pack/plugins/observability_solution/uptime/e2e/tsconfig.json index 84a2627b487fe..2ad789f1e88d9 100644 --- a/x-pack/plugins/observability_solution/uptime/e2e/tsconfig.json +++ b/x-pack/plugins/observability_solution/uptime/e2e/tsconfig.json @@ -13,6 +13,7 @@ "@kbn/ux-plugin/e2e", "@kbn/ftr-common-functional-services", "@kbn/apm-plugin", - "@kbn/es-archiver" + "@kbn/es-archiver", + "@kbn/ftr-common-functional-ui-services" ] } diff --git a/x-pack/test/api_integration/apis/cloud_security_posture/helper.ts b/x-pack/test/api_integration/apis/cloud_security_posture/helper.ts index 13bc2ee7de9d2..7c21e6df09f8c 100644 --- a/x-pack/test/api_integration/apis/cloud_security_posture/helper.ts +++ b/x-pack/test/api_integration/apis/cloud_security_posture/helper.ts @@ -11,7 +11,7 @@ import expect from '@kbn/expect'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import type { IndexDetails } from '@kbn/cloud-security-posture-common'; import { CLOUD_SECURITY_PLUGIN_VERSION } from '@kbn/cloud-security-posture-plugin/common/constants'; -import { SecurityService } from '@kbn/test-suites-src/common/services/security/security'; +import { SecurityService } from '@kbn/ftr-common-functional-ui-services'; export interface RoleCredentials { apiKey: { id: string; name: string }; diff --git a/x-pack/test/api_integration/apis/telemetry/telemetry.ts b/x-pack/test/api_integration/apis/telemetry/telemetry.ts index bae5c5b8cdc44..5e034ce3a1847 100644 --- a/x-pack/test/api_integration/apis/telemetry/telemetry.ts +++ b/x-pack/test/api_integration/apis/telemetry/telemetry.ts @@ -26,7 +26,7 @@ import { ELASTIC_HTTP_VERSION_HEADER, X_ELASTIC_INTERNAL_ORIGIN_REQUEST, } from '@kbn/core-http-common'; -import type { SecurityService } from '@kbn/test-suites-src/common/services/security/security'; +import type { SecurityService } from '@kbn/ftr-common-functional-ui-services'; import basicClusterFixture from './fixtures/basiccluster.json'; import multiClusterFixture from './fixtures/multicluster.json'; import type { FtrProviderContext } from '../../ftr_provider_context'; diff --git a/x-pack/test/common/services/bsearch_secure.ts b/x-pack/test/common/services/bsearch_secure.ts index f454aa3818ea6..ccd1866ddd66e 100644 --- a/x-pack/test/common/services/bsearch_secure.ts +++ b/x-pack/test/common/services/bsearch_secure.ts @@ -5,8 +5,8 @@ * 2.0. */ -// NOTE: This is pretty much a copy/paste from test/common/services/bsearch.ts but with the ability -// to provide custom auth +// NOTE: This is pretty much a copy/paste from packages/kbn-ftr-common-functional-services/services/bsearch.ts +// but with the ability to provide custom auth import expect from '@kbn/expect'; import request from 'superagent'; diff --git a/x-pack/test/common/services/index.ts b/x-pack/test/common/services/index.ts index 5e931b440654a..edf64c828e944 100644 --- a/x-pack/test/common/services/index.ts +++ b/x-pack/test/common/services/index.ts @@ -6,7 +6,8 @@ */ import { services as kibanaApiIntegrationServices } from '@kbn/test-suites-src/api_integration/services'; -import { services as kibanaCommonServices } from '@kbn/test-suites-src/common/services'; +import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; +import { commonFunctionalUIServices } from '@kbn/ftr-common-functional-ui-services'; import { InfraLogViewsServiceProvider } from './infra_log_views'; import { SpacesServiceProvider } from './spaces'; import { BsearchSecureService } from './bsearch_secure'; @@ -14,7 +15,8 @@ import { ApmSynthtraceKibanaClientProvider } from './apm_synthtrace_kibana_clien import { InfraSynthtraceKibanaClientProvider } from './infra_synthtrace_kibana_client'; export const services = { - ...kibanaCommonServices, + ...commonFunctionalServices, + ...commonFunctionalUIServices, infraLogViews: InfraLogViewsServiceProvider, supertest: kibanaApiIntegrationServices.supertest, spaces: SpacesServiceProvider, diff --git a/x-pack/test/fleet_api_integration/apis/test_users.ts b/x-pack/test/fleet_api_integration/apis/test_users.ts index f84c1f72fb657..74581fd681af7 100644 --- a/x-pack/test/fleet_api_integration/apis/test_users.ts +++ b/x-pack/test/fleet_api_integration/apis/test_users.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { SecurityService } from '@kbn/test-suites-src/common/services/security/security'; +import type { SecurityService } from '@kbn/ftr-common-functional-ui-services'; export const testUsers: { [rollName: string]: { username: string; password: string; permissions?: any }; diff --git a/x-pack/test/fleet_cypress/config.ts b/x-pack/test/fleet_cypress/config.ts index da0d8aa7af271..d868be18bc5c3 100644 --- a/x-pack/test/fleet_cypress/config.ts +++ b/x-pack/test/fleet_cypress/config.ts @@ -6,7 +6,6 @@ */ import { FtrConfigProviderContext, getKibanaCliLoggers } from '@kbn/test'; - import { CA_CERT_PATH } from '@kbn/dev-utils'; export default async function ({ readConfigFile }: FtrConfigProviderContext) { diff --git a/x-pack/test/functional_enterprise_search/cli_config.ts b/x-pack/test/functional_enterprise_search/cli_config.ts index 05fe67f6be01a..ce439961848c8 100644 --- a/x-pack/test/functional_enterprise_search/cli_config.ts +++ b/x-pack/test/functional_enterprise_search/cli_config.ts @@ -6,6 +6,8 @@ */ import { FtrConfigProviderContext } from '@kbn/test'; +import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; +import { commonFunctionalUIServices } from '@kbn/ftr-common-functional-ui-services'; import { EnterpriseSearchCypressCliTestRunner } from './runner'; export default async function ({ readConfigFile }: FtrConfigProviderContext) { @@ -16,6 +18,12 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { return { ...kibanaCommonTestsConfig.getAll(), + + services: { + ...commonFunctionalServices, + ...commonFunctionalUIServices, + }, + // default to the xpack functional config ...baseConfig.getAll(), diff --git a/x-pack/test/osquery_cypress/services.ts b/x-pack/test/osquery_cypress/services.ts index 272cf7eb8da4e..95fd493e6f668 100644 --- a/x-pack/test/osquery_cypress/services.ts +++ b/x-pack/test/osquery_cypress/services.ts @@ -5,4 +5,10 @@ * 2.0. */ -export * from '@kbn/test-suites-src/common/services'; +import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; +import { commonFunctionalUIServices } from '@kbn/ftr-common-functional-ui-services'; + +export const services = { + ...commonFunctionalServices, + ...commonFunctionalUIServices, +} as const; diff --git a/x-pack/test/profiling_api_integration/common/create_profiling_users/helpers/create_or_update_user.ts b/x-pack/test/profiling_api_integration/common/create_profiling_users/helpers/create_or_update_user.ts index 679a750af410b..2f467d4507e7f 100644 --- a/x-pack/test/profiling_api_integration/common/create_profiling_users/helpers/create_or_update_user.ts +++ b/x-pack/test/profiling_api_integration/common/create_profiling_users/helpers/create_or_update_user.ts @@ -8,7 +8,7 @@ /* eslint-disable no-console */ import { difference, union } from 'lodash'; -import { SecurityService } from '@kbn/test-suites-src/common/services/security/security'; +import type { SecurityService } from '@kbn/ftr-common-functional-ui-services'; import { Elasticsearch, Kibana } from '..'; import { callKibana, isAxiosError } from './call_kibana'; diff --git a/x-pack/test/profiling_api_integration/common/create_profiling_users/index.ts b/x-pack/test/profiling_api_integration/common/create_profiling_users/index.ts index d7c101dd52eaa..18a056b001c56 100644 --- a/x-pack/test/profiling_api_integration/common/create_profiling_users/index.ts +++ b/x-pack/test/profiling_api_integration/common/create_profiling_users/index.ts @@ -5,7 +5,7 @@ * 2.0. */ import { asyncForEach } from '@kbn/std'; -import { SecurityService } from '@kbn/test-suites-src/common/services/security/security'; +import type { SecurityService } from '@kbn/ftr-common-functional-ui-services'; import { ProfilingUsername, profilingUsers } from './authentication'; import { AbortError, callKibana } from './helpers/call_kibana'; import { createOrUpdateUser } from './helpers/create_or_update_user'; diff --git a/x-pack/test/saved_objects_field_count/config.ts b/x-pack/test/saved_objects_field_count/config.ts index eb2aeb1df90a9..603a325ca0479 100644 --- a/x-pack/test/saved_objects_field_count/config.ts +++ b/x-pack/test/saved_objects_field_count/config.ts @@ -6,6 +6,7 @@ */ import { FtrConfigProviderContext } from '@kbn/test'; +import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; export default async function ({ readConfigFile }: FtrConfigProviderContext) { const kibanaCommonTestsConfig = await readConfigFile( @@ -15,6 +16,10 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { return { ...kibanaCommonTestsConfig.getAll(), + services: { + ...commonFunctionalServices, + }, + testFiles: [require.resolve('./test')], esTestCluster: { diff --git a/x-pack/test/security_solution_api_integration/config/services/security_solution_serverless_utils.ts b/x-pack/test/security_solution_api_integration/config/services/security_solution_serverless_utils.ts index da57ccf64860e..00df4f0374c27 100644 --- a/x-pack/test/security_solution_api_integration/config/services/security_solution_serverless_utils.ts +++ b/x-pack/test/security_solution_api_integration/config/services/security_solution_serverless_utils.ts @@ -9,7 +9,7 @@ import supertest from 'supertest'; import { format as formatUrl } from 'url'; import { IEsSearchResponse } from '@kbn/search-types'; import { RoleCredentials } from '@kbn/test-suites-serverless/shared/services'; -import type { SendOptions } from '@kbn/test-suites-src/common/services/bsearch'; +import type { SendOptions } from '@kbn/ftr-common-functional-services'; import type { SendOptions as SecureBsearchSendOptions } from '@kbn/test-suites-serverless/shared/services/bsearch_secure'; import type { FtrProviderContext } from '../../ftr_provider_context'; import type { SecuritySolutionUtilsInterface } from './types'; diff --git a/x-pack/test/security_solution_api_integration/config/services/types.ts b/x-pack/test/security_solution_api_integration/config/services/types.ts index 72397582dad00..838f31e69412e 100644 --- a/x-pack/test/security_solution_api_integration/config/services/types.ts +++ b/x-pack/test/security_solution_api_integration/config/services/types.ts @@ -9,7 +9,7 @@ import TestAgent from 'supertest/lib/agent'; import type { IEsSearchResponse } from '@kbn/search-types'; import type { BsearchSecureService } from '@kbn/test-suites-serverless/shared/services/bsearch_secure'; -import type { BsearchService, SendOptions } from '@kbn/test-suites-src/common/services/bsearch'; +import type { BsearchService, SendOptions } from '@kbn/ftr-common-functional-services'; export interface SecuritySolutionServerlessBsearch extends Omit { send: (options: SendOptions) => Promise; diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/users_and_roles.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/users_and_roles.ts index 3bccaf4a00fe3..a9663cd943a78 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/users_and_roles.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/users_and_roles.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { SecurityService } from '@kbn/test-suites-src/common/services/security/security'; +import type { SecurityService } from '@kbn/ftr-common-functional-ui-services'; export const usersAndRolesFactory = (security: SecurityService) => ({ createRole: async ({ name, privileges }: { name: string; privileges: any }) => { diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/host_details.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/host_details.ts index 1c74a987e4fec..cf2ac65f1086b 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/host_details.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/host_details.ts @@ -11,7 +11,7 @@ import { HostsQueries, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/test-suites-src/common/services/bsearch'; +import { BsearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; import { hostDetailsFilebeatExpectedResult } from '../mocks/host_details'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/hosts.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/hosts.ts index 1cff93fd1bc13..6fdbfec48f161 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/hosts.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/hosts.ts @@ -16,7 +16,7 @@ import { FirstLastSeenStrategyResponse, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/test-suites-src/common/services/bsearch'; +import { BsearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/uncommon_processes.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/uncommon_processes.ts index 19710d4eedf45..22001c26b66b5 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/uncommon_processes.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/uncommon_processes.ts @@ -12,7 +12,7 @@ import { HostsUncommonProcessesStrategyResponse, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/test-suites-src/common/services/bsearch'; +import { BsearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; const FROM = '2000-01-01T00:00:00.000Z'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_details.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_details.ts index 5e9040424713b..166af42ba5702 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_details.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_details.ts @@ -11,7 +11,7 @@ import { NetworkQueries, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/test-suites-src/common/services/bsearch'; +import { BsearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_dns.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_dns.ts index 7254dc6e99a5e..22edc8cff64de 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_dns.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_dns.ts @@ -14,7 +14,7 @@ import { NetworkDnsStrategyResponse, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/test-suites-src/common/services/bsearch'; +import { BsearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; export default function ({ getService }: FtrProviderContextWithSpaces) { diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_top_n_flow.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_top_n_flow.ts index 2306861471073..8b1adb16975f6 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_top_n_flow.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_top_n_flow.ts @@ -15,7 +15,7 @@ import { NetworkTopNFlowStrategyResponse, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/test-suites-src/common/services/bsearch'; +import { BsearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/tls.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/tls.ts index 4c555ca0d6555..36b2b677a1949 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/tls.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/tls.ts @@ -14,7 +14,8 @@ import { NetworkTlsStrategyResponse, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/test-suites-src/common/services/bsearch'; + +import { BsearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/overview/trial_license_complete_tier/tests/overview_host.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/overview/trial_license_complete_tier/tests/overview_host.ts index d99fbd296ba3e..ffb287239ac0f 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/overview/trial_license_complete_tier/tests/overview_host.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/overview/trial_license_complete_tier/tests/overview_host.ts @@ -12,7 +12,7 @@ import { HostsOverviewStrategyResponse, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/test-suites-src/common/services/bsearch'; +import { BsearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; export default function ({ getService }: FtrProviderContextWithSpaces) { diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/overview/trial_license_complete_tier/tests/overview_network.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/overview/trial_license_complete_tier/tests/overview_network.ts index 952e3eed8f8af..f8d4aa80c0e3d 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/overview/trial_license_complete_tier/tests/overview_network.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/overview/trial_license_complete_tier/tests/overview_network.ts @@ -11,7 +11,7 @@ import { NetworkQueries, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/test-suites-src/common/services/bsearch'; +import { BsearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; export default function ({ getService }: FtrProviderContextWithSpaces) { diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/users/trial_license_complete_tier/tests/authentications.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/users/trial_license_complete_tier/tests/authentications.ts index d7329a597e2e0..39dddc7a0c046 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/users/trial_license_complete_tier/tests/authentications.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/users/trial_license_complete_tier/tests/authentications.ts @@ -15,7 +15,7 @@ import { import type { UserAuthenticationsRequestOptions } from '@kbn/security-solution-plugin/common/api/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/test-suites-src/common/services/bsearch'; +import { BsearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; const FROM = '2000-01-01T00:00:00.000Z'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/users/trial_license_complete_tier/tests/users.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/users/trial_license_complete_tier/tests/users.ts index 65b44bf4cbc5e..6765e6d2bb164 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/users/trial_license_complete_tier/tests/users.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/users/trial_license_complete_tier/tests/users.ts @@ -14,7 +14,8 @@ import { NetworkUsersStrategyResponse, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/test-suites-src/common/services/bsearch'; + +import { BsearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/events.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/events.ts index c66978bbe1b42..c42ac64de4a23 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/events.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/events.ts @@ -14,8 +14,9 @@ import { TimelineEventsAllStrategyResponse, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/test-suites-src/common/services/bsearch'; +import { BsearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; + import { getFieldsToRequest, getFilterValue } from '../../../../utils'; const TO = '3000-01-01T00:00:00.000Z'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/timeline_details.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/timeline_details.ts index 1e3119260455d..12539d43a145f 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/timeline_details.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/timeline_details.ts @@ -13,7 +13,8 @@ import { TimelineKpiStrategyResponse, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/test-suites-src/common/services/bsearch'; + +import { BsearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; import { timelineDetailsFilebeatExpectedResults as EXPECTED_DATA } from '../mocks/timeline_details'; diff --git a/x-pack/test/security_solution_api_integration/tsconfig.json b/x-pack/test/security_solution_api_integration/tsconfig.json index 2f420920027d5..1f558e3c3f051 100644 --- a/x-pack/test/security_solution_api_integration/tsconfig.json +++ b/x-pack/test/security_solution_api_integration/tsconfig.json @@ -49,6 +49,6 @@ "@kbn/dev-cli-runner", "@kbn/search-types", "@kbn/security-plugin", - "@kbn/test-suites-src", + "@kbn/ftr-common-functional-ui-services", ] } diff --git a/x-pack/test/threat_intelligence_cypress/config.ts b/x-pack/test/threat_intelligence_cypress/config.ts index 963cfab55dad5..c2e9a6ac8b180 100644 --- a/x-pack/test/threat_intelligence_cypress/config.ts +++ b/x-pack/test/threat_intelligence_cypress/config.ts @@ -6,9 +6,8 @@ */ import { FtrConfigProviderContext } from '@kbn/test'; - import { CA_CERT_PATH } from '@kbn/dev-utils'; - +import { services } from './services'; export default async function ({ readConfigFile }: FtrConfigProviderContext) { const kibanaCommonTestsConfig = await readConfigFile( require.resolve('@kbn/test-suites-src/common/config') @@ -20,6 +19,8 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { return { ...kibanaCommonTestsConfig.getAll(), + services, + esTestCluster: { ...xpackFunctionalTestsConfig.get('esTestCluster'), serverArgs: [ diff --git a/x-pack/test/upgrade_assistant_integration/config.js b/x-pack/test/upgrade_assistant_integration/config.js index dbdf0ade8affe..9529e4bc568d3 100644 --- a/x-pack/test/upgrade_assistant_integration/config.js +++ b/x-pack/test/upgrade_assistant_integration/config.js @@ -5,6 +5,8 @@ * 2.0. */ +import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; + export default async function ({ readConfigFile }) { // Read the Kibana API integration tests config file so that we can utilize its services. const kibanaAPITestsConfig = await readConfigFile( @@ -13,15 +15,12 @@ export default async function ({ readConfigFile }) { const xPackFunctionalTestsConfig = await readConfigFile( require.resolve('../functional/config.base.js') ); - const kibanaCommonConfig = await readConfigFile( - require.resolve('@kbn/test-suites-src/common/config') - ); return { testFiles: [require.resolve('./upgrade_assistant')], servers: xPackFunctionalTestsConfig.get('servers'), services: { - ...kibanaCommonConfig.get('services'), + ...commonFunctionalServices, supertest: kibanaAPITestsConfig.get('services.supertest'), }, junit: { diff --git a/x-pack/test_serverless/api_integration/test_suites/common/console/autocomplete_entities.ts b/x-pack/test_serverless/api_integration/test_suites/common/console/autocomplete_entities.ts index 72640103c0ef9..3ec162ad28ffd 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/console/autocomplete_entities.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/console/autocomplete_entities.ts @@ -11,7 +11,7 @@ import { InternalRequestHeader, RoleCredentials } from '../../../../shared/servi export default ({ getService }: FtrProviderContext) => { const svlCommonApi = getService('svlCommonApi'); - const consoleService = getService('console'); + const console = getService('console'); const svlUserManager = getService('svlUserManager'); const supertestWithoutAuth = getService('supertestWithoutAuth'); @@ -27,17 +27,6 @@ export default ({ getService }: FtrProviderContext) => { }; describe('/api/console/autocomplete_entities', function () { - let createIndex: (typeof consoleService)['helpers']['createIndex']; - let createAlias: (typeof consoleService)['helpers']['createAlias']; - let createIndexTemplate: (typeof consoleService)['helpers']['createIndexTemplate']; - let createComponentTemplate: (typeof consoleService)['helpers']['createComponentTemplate']; - let createDataStream: (typeof consoleService)['helpers']['createDataStream']; - let deleteIndex: (typeof consoleService)['helpers']['deleteIndex']; - let deleteAlias: (typeof consoleService)['helpers']['deleteAlias']; - let deleteIndexTemplate: (typeof consoleService)['helpers']['deleteIndexTemplate']; - let deleteComponentTemplate: (typeof consoleService)['helpers']['deleteComponentTemplate']; - let deleteDataStream: (typeof consoleService)['helpers']['deleteDataStream']; - const indexName = 'test-index-1'; const aliasName = 'test-alias-1'; const indexTemplateName = 'test-index-template-1'; @@ -47,36 +36,26 @@ export default ({ getService }: FtrProviderContext) => { before(async () => { roleAuthc = await svlUserManager.createM2mApiKeyWithRoleScope('admin'); internalRequestHeader = svlCommonApi.getInternalRequestHeader(); - ({ - helpers: { - createIndex, - createAlias, - createIndexTemplate, - createComponentTemplate, - createDataStream, - deleteIndex, - deleteAlias, - deleteIndexTemplate, - deleteComponentTemplate, - deleteDataStream, - }, - } = consoleService); // Setup indices, aliases, templates, and data streams - await createIndex(indexName); - await createAlias(indexName, aliasName); - await createComponentTemplate(componentTemplateName); - await createIndexTemplate(indexTemplateName, [dataStreamName], [componentTemplateName]); - await createDataStream(dataStreamName); + await console.createIndex(indexName); + await console.createAlias(indexName, aliasName); + await console.createComponentTemplate(componentTemplateName); + await console.createIndexTemplate( + indexTemplateName, + [dataStreamName], + [componentTemplateName] + ); + await console.createDataStream(dataStreamName); }); after(async () => { // Cleanup indices, aliases, templates, and data streams - await deleteAlias(indexName, aliasName); - await deleteIndex(indexName); - await deleteDataStream(dataStreamName); - await deleteIndexTemplate(indexTemplateName); - await deleteComponentTemplate(componentTemplateName); + await console.deleteAlias(indexName, aliasName); + await console.deleteIndex(indexName); + await console.deleteDataStream(dataStreamName); + await console.deleteIndexTemplate(indexTemplateName); + await console.deleteComponentTemplate(componentTemplateName); await svlUserManager.invalidateM2mApiKeyWithRoleScope(roleAuthc); }); diff --git a/x-pack/test_serverless/shared/services/bsearch_secure.ts b/x-pack/test_serverless/shared/services/bsearch_secure.ts index 7ebe89bed8247..03f8241c9e12a 100644 --- a/x-pack/test_serverless/shared/services/bsearch_secure.ts +++ b/x-pack/test_serverless/shared/services/bsearch_secure.ts @@ -5,8 +5,8 @@ * 2.0. */ -// NOTE: This is pretty much a copy/paste from test/common/services/bsearch.ts but with the ability -// to provide custom auth +// NOTE: This is pretty much a copy/paste from packages/kbn-ftr-common-functional-services/services/bsearch.ts +// but with the ability to provide custom auth import expect from '@kbn/expect'; import { GenericFtrService } from '@kbn/test'; From c07e946e0cc66db5ca9a6b7256f0f6b73ece04ea Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 5 Sep 2024 11:36:24 +0200 Subject: [PATCH 23/99] [Synthetics] Use msearch for multiple queries !! (#192065) ## Summary Use msearch for multiple queries for overview status !! Also refactored to create separate query for status alert rule instead of reusing !! --- .../status_rule/query_monitor_status_alert.ts | 218 ++++++ .../status_rule/status_rule_executor.ts | 4 +- .../synthetics/server/lib.ts | 54 +- .../server/queries/query_monitor_status.ts | 301 ++++---- .../overview_status/overview_status.test.ts | 700 +++++++++--------- 5 files changed, 779 insertions(+), 498 deletions(-) create mode 100644 x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/query_monitor_status_alert.ts diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/query_monitor_status_alert.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/query_monitor_status_alert.ts new file mode 100644 index 0000000000000..1433c45d1becf --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/query_monitor_status_alert.ts @@ -0,0 +1,218 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import pMap from 'p-map'; +import times from 'lodash/times'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { cloneDeep, intersection } from 'lodash'; +import { createEsParams, SyntheticsEsClient } from '../../lib'; +import { + OverviewPendingStatusMetaData, + OverviewPing, + OverviewStatus, + OverviewStatusMetaData, +} from '../../../common/runtime_types'; +import { FINAL_SUMMARY_FILTER } from '../../../common/constants/client_defaults'; + +const DEFAULT_MAX_ES_BUCKET_SIZE = 10000; + +const fields = [ + '@timestamp', + 'summary', + 'monitor', + 'observer', + 'config_id', + 'error', + 'agent', + 'url', + 'state', + 'tags', +]; + +export async function queryMonitorStatusForAlert( + esClient: SyntheticsEsClient, + monitorLocationIds: string[], + range: { from: string; to: string }, + monitorQueryIds: string[], + monitorLocationsMap: Record, + monitorQueryIdToConfigIdMap: Record +): Promise< + Omit< + OverviewStatus, + | 'disabledCount' + | 'allMonitorsCount' + | 'disabledMonitorsCount' + | 'projectMonitorsCount' + | 'disabledMonitorQueryIds' + | 'allIds' + > +> { + const idSize = Math.trunc(DEFAULT_MAX_ES_BUCKET_SIZE / monitorLocationIds.length || 1); + const pageCount = Math.ceil(monitorQueryIds.length / idSize); + let up = 0; + let down = 0; + const upConfigs: Record = {}; + const downConfigs: Record = {}; + const monitorsWithoutData = new Map(Object.entries(cloneDeep(monitorLocationsMap))); + const pendingConfigs: Record = {}; + + await pMap( + times(pageCount), + async (i) => { + const idsToQuery = (monitorQueryIds as string[]).slice(i * idSize, i * idSize + idSize); + const params = createEsParams({ + body: { + size: 0, + query: { + bool: { + filter: [ + FINAL_SUMMARY_FILTER, + { + range: { + '@timestamp': { + gte: range.from, + lte: range.to, + }, + }, + }, + { + terms: { + 'monitor.id': idsToQuery, + }, + }, + ] as QueryDslQueryContainer[], + }, + }, + aggs: { + id: { + terms: { + field: 'monitor.id', + size: idSize, + }, + aggs: { + location: { + terms: { + field: 'observer.name', + size: monitorLocationIds.length || 100, + }, + aggs: { + status: { + top_hits: { + size: 1, + sort: [ + { + '@timestamp': { + order: 'desc', + }, + }, + ], + _source: { + includes: fields, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }); + + if (monitorLocationIds.length > 0) { + params.body.query.bool.filter.push({ + terms: { + 'observer.name': monitorLocationIds, + }, + }); + } + + const { body: result } = await esClient.search( + params, + 'getCurrentStatusOverview' + i + ); + + result.aggregations?.id.buckets.forEach(({ location, key: queryId }) => { + const locationSummaries = location.buckets.map(({ status, key: locationName }) => { + const ping = status.hits.hits[0]._source; + return { location: locationName, ping }; + }); + + // discard any locations that are not in the monitorLocationsMap for the given monitor as well as those which are + // in monitorLocationsMap but not in listOfLocations + const monLocations = monitorLocationsMap?.[queryId]; + const monQueriedLocations = intersection(monLocations, monitorLocationIds); + monQueriedLocations?.forEach((monLocation) => { + const locationSummary = locationSummaries.find( + (summary) => summary.location === monLocation + ); + + if (locationSummary) { + const { ping } = locationSummary; + const downCount = ping.summary?.down ?? 0; + const upCount = ping.summary?.up ?? 0; + const configId = ping.config_id; + const monitorQueryId = ping.monitor.id; + + const meta = { + ping, + configId, + monitorQueryId, + locationId: monLocation, + timestamp: ping['@timestamp'], + }; + + if (downCount > 0) { + down += 1; + downConfigs[`${configId}-${monLocation}`] = { + ...meta, + status: 'down', + }; + } else if (upCount > 0) { + up += 1; + upConfigs[`${configId}-${monLocation}`] = { + ...meta, + status: 'up', + }; + } + const monitorsMissingData = monitorsWithoutData.get(monitorQueryId) || []; + monitorsWithoutData.set( + monitorQueryId, + monitorsMissingData?.filter((loc) => loc !== monLocation) + ); + if (!monitorsWithoutData.get(monitorQueryId)?.length) { + monitorsWithoutData.delete(monitorQueryId); + } + } + }); + }); + }, + { concurrency: 5 } + ); + + // identify the remaining monitors without data, to determine pending monitors + for (const [queryId, locs] of monitorsWithoutData) { + locs.forEach((loc) => { + pendingConfigs[`${monitorQueryIdToConfigIdMap[queryId]}-${loc}`] = { + configId: `${monitorQueryIdToConfigIdMap[queryId]}`, + monitorQueryId: queryId, + status: 'unknown', + locationId: loc, + }; + }); + } + + return { + up, + down, + pending: Object.values(pendingConfigs).length, + upConfigs, + downConfigs, + pendingConfigs, + enabledMonitorQueryIds: monitorQueryIds, + }; +} diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/status_rule_executor.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/status_rule_executor.ts index 4d5ab04d6c10f..c947c0db131eb 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/status_rule_executor.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/status_rule_executor.ts @@ -10,6 +10,7 @@ import { SavedObjectsFindResult, } from '@kbn/core-saved-objects-api-server'; import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { queryMonitorStatusForAlert } from './query_monitor_status_alert'; import { SyntheticsServerSetup } from '../../types'; import { SyntheticsEsClient } from '../../lib'; import { SYNTHETICS_INDEX_PATTERN } from '../../../common/constants'; @@ -17,7 +18,6 @@ import { getAllMonitors, processMonitors, } from '../../saved_objects/synthetics_monitor/get_all_monitors'; -import { queryMonitorStatus } from '../../queries/query_monitor_status'; import { StatusRuleParams } from '../../../common/rules/status_rule'; import { ConfigKey, @@ -107,7 +107,7 @@ export class StatusRuleExecutor { : 'now-2m'; if (enabledMonitorQueryIds.length > 0) { - const currentStatus = await queryMonitorStatus( + const currentStatus = await queryMonitorStatusForAlert( this.esClient, monitorLocationIds, { diff --git a/x-pack/plugins/observability_solution/synthetics/server/lib.ts b/x-pack/plugins/observability_solution/synthetics/server/lib.ts index 63d511a2d2063..7aff6a6ab08e0 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/lib.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/lib.ts @@ -78,7 +78,6 @@ export class SyntheticsEsClient { const esParams = { index: SYNTHETICS_INDEX_PATTERN, ...params }; const startTime = process.hrtime(); - const startTimeNow = Date.now(); let esRequestStatus: RequestStatus = RequestStatus.PENDING; @@ -90,7 +89,8 @@ export class SyntheticsEsClient { esError = e; esRequestStatus = RequestStatus.ERROR; } - if (this.request) { + const isInspectorEnabled = await this.getInspectEnabled(); + if (isInspectorEnabled && this.request) { this.inspectableEsQueries.push( getInspectResponse({ esError, @@ -102,9 +102,7 @@ export class SyntheticsEsClient { startTime: startTimeNow, }) ); - } - const isInspectorEnabled = await this.getInspectEnabled(); - if (isInspectorEnabled && this.request) { + debugESCall({ startTime, request: this.request, @@ -125,7 +123,8 @@ export class SyntheticsEsClient { TSearchRequest extends estypes.SearchRequest = estypes.SearchRequest, TDocument = unknown >( - requests: MsearchMultisearchBody[] + requests: MsearchMultisearchBody[], + operationName?: string ): Promise<{ responses: Array> }> { const searches: Array = []; for (const request of requests) { @@ -133,15 +132,41 @@ export class SyntheticsEsClient { searches.push(request); } - const results = await this.baseESClient.msearch( - { - searches, - }, - { meta: true } - ); + const startTimeNow = Date.now(); + + let res: any; + let esError: any; + + try { + res = await this.baseESClient.msearch( + { + searches, + }, + { meta: true } + ); + } catch (e) { + esError = e; + } + + const isInspectorEnabled = await this.getInspectEnabled(); + if (isInspectorEnabled && this.request) { + requests.forEach((request, index) => { + this.inspectableEsQueries.push( + getInspectResponse({ + esError, + esRequestParams: { index: SYNTHETICS_INDEX_PATTERN, ...request }, + esRequestStatus: RequestStatus.OK, + esResponse: res.body.responses[index], + kibanaRequest: this.request!, + operationName: operationName ?? '', + startTime: startTimeNow, + }) + ); + }); + } return { - responses: results.body.responses as unknown as Array< + responses: res.body.responses as unknown as Array< InferSearchResponseOf >, }; @@ -193,6 +218,9 @@ export class SyntheticsEsClient { return {}; } async getInspectEnabled() { + if (this.isDev) { + return true; + } if (!this.uiSettings) { return false; } diff --git a/x-pack/plugins/observability_solution/synthetics/server/queries/query_monitor_status.ts b/x-pack/plugins/observability_solution/synthetics/server/queries/query_monitor_status.ts index 2bed9fdb5f643..e2302ed638102 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/queries/query_monitor_status.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/queries/query_monitor_status.ts @@ -5,10 +5,10 @@ * 2.0. */ -import pMap from 'p-map'; import times from 'lodash/times'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { cloneDeep, intersection } from 'lodash'; +import { MsearchMultisearchBody } from '@elastic/elasticsearch/lib/api/types'; import { FINAL_SUMMARY_FILTER } from '../../common/constants/client_defaults'; import { OverviewPendingStatusMetaData, @@ -33,87 +33,67 @@ const fields = [ 'tags', ]; -export async function queryMonitorStatus( - esClient: SyntheticsEsClient, - monitorLocationIds: string[], - range: { from: string; to: string }, - monitorQueryIds: string[], - monitorLocationsMap: Record, - monitorQueryIdToConfigIdMap: Record -): Promise< - Omit< - OverviewStatus, - | 'disabledCount' - | 'allMonitorsCount' - | 'disabledMonitorsCount' - | 'projectMonitorsCount' - | 'disabledMonitorQueryIds' - | 'allIds' - > -> { - const idSize = Math.trunc(DEFAULT_MAX_ES_BUCKET_SIZE / monitorLocationIds.length || 1); - const pageCount = Math.ceil(monitorQueryIds.length / idSize); - let up = 0; - let down = 0; - const upConfigs: Record = {}; - const downConfigs: Record = {}; - const monitorsWithoutData = new Map(Object.entries(cloneDeep(monitorLocationsMap))); - const pendingConfigs: Record = {}; - - await pMap( - times(pageCount), - async (i) => { - const idsToQuery = (monitorQueryIds as string[]).slice(i * idSize, i * idSize + idSize); - const params = createEsParams({ - body: { - size: 0, - query: { - bool: { - filter: [ - FINAL_SUMMARY_FILTER, - { - range: { - '@timestamp': { - gte: range.from, - lte: range.to, - }, - }, - }, - { - terms: { - 'monitor.id': idsToQuery, - }, +const getStatusQuery = ({ + idsToQuery, + range, + monitorLocationIds, + idSize, +}: { + idSize: number; + monitorLocationIds: string[]; + range: { from: string; to: string }; + idsToQuery: string[]; + monitorLocationsMap: Record; + monitorQueryIdToConfigIdMap: Record; +}) => { + const params = createEsParams({ + body: { + size: 0, + query: { + bool: { + filter: [ + FINAL_SUMMARY_FILTER, + { + range: { + '@timestamp': { + gte: range.from, + lte: range.to, }, - ] as QueryDslQueryContainer[], + }, }, + { + terms: { + 'monitor.id': idsToQuery, + }, + }, + ] as QueryDslQueryContainer[], + }, + }, + aggs: { + id: { + terms: { + field: 'monitor.id', + size: idSize, }, aggs: { - id: { + location: { terms: { - field: 'monitor.id', - size: idSize, + field: 'observer.name', + size: monitorLocationIds.length || 100, }, aggs: { - location: { - terms: { - field: 'observer.name', - size: monitorLocationIds.length || 100, - }, - aggs: { - status: { - top_hits: { - size: 1, - sort: [ - { - '@timestamp': { - order: 'desc', - }, - }, - ], - _source: { - includes: fields, + status: { + top_hits: { + size: 1, + sort: [ + { + '@timestamp': { + order: 'desc', }, }, + ], + _source: { + includes: fields, }, }, }, @@ -121,78 +101,121 @@ export async function queryMonitorStatus( }, }, }, + }, + }, + }); + + if (monitorLocationIds.length > 0) { + params.body.query?.bool?.filter.push({ + terms: { + 'observer.name': monitorLocationIds, + }, + }); + } + return params; +}; + +type StatusQueryParams = ReturnType; +type OverviewStatusResponse = Omit< + OverviewStatus, + | 'disabledCount' + | 'allMonitorsCount' + | 'disabledMonitorsCount' + | 'projectMonitorsCount' + | 'disabledMonitorQueryIds' + | 'allIds' +>; + +export async function queryMonitorStatus( + esClient: SyntheticsEsClient, + monitorLocationIds: string[], + range: { from: string; to: string }, + monitorQueryIds: string[], + monitorLocationsMap: Record, + monitorQueryIdToConfigIdMap: Record +): Promise { + const idSize = Math.trunc(DEFAULT_MAX_ES_BUCKET_SIZE / monitorLocationIds.length || 1); + const pageCount = Math.ceil(monitorQueryIds.length / idSize); + let up = 0; + let down = 0; + const upConfigs: Record = {}; + const downConfigs: Record = {}; + const monitorsWithoutData = new Map(Object.entries(cloneDeep(monitorLocationsMap))); + const pendingConfigs: Record = {}; + + const queries: MsearchMultisearchBody[] = times(pageCount).map((i) => { + const idsToQuery = (monitorQueryIds as string[]).slice(i * idSize, i * idSize + idSize); + return getStatusQuery({ + idSize, + monitorLocationIds, + range, + idsToQuery, + monitorLocationsMap, + monitorQueryIdToConfigIdMap, + }).body; + }); + + const { responses } = await esClient.msearch( + queries, + 'getCurrentStatusOverview' + ); + + responses.forEach((result) => { + result.aggregations?.id.buckets.forEach(({ location, key: queryId }) => { + const locationSummaries = location.buckets.map(({ status, key: locationName }) => { + const ping = status.hits.hits[0]._source; + return { location: locationName, ping }; }); - if (monitorLocationIds.length > 0) { - params.body.query.bool.filter.push({ - terms: { - 'observer.name': monitorLocationIds, - }, - }); - } - - const { body: result } = await esClient.search( - params, - 'getCurrentStatusOverview' + i - ); - - result.aggregations?.id.buckets.forEach(({ location, key: queryId }) => { - const locationSummaries = location.buckets.map(({ status, key: locationName }) => { - const ping = status.hits.hits[0]._source; - return { location: locationName, ping }; - }); - - // discard any locations that are not in the monitorLocationsMap for the given monitor as well as those which are - // in monitorLocationsMap but not in listOfLocations - const monLocations = monitorLocationsMap?.[queryId]; - const monQueriedLocations = intersection(monLocations, monitorLocationIds); - monQueriedLocations?.forEach((monLocation) => { - const locationSummary = locationSummaries.find( - (summary) => summary.location === monLocation - ); + // discard any locations that are not in the monitorLocationsMap for the given monitor as well as those which are + // in monitorLocationsMap but not in listOfLocations + const monLocations = monitorLocationsMap?.[queryId]; + const monQueriedLocations = intersection(monLocations, monitorLocationIds); + monQueriedLocations?.forEach((monLocation) => { + const locationSummary = locationSummaries.find( + (summary) => summary.location === monLocation + ); - if (locationSummary) { - const { ping } = locationSummary; - const downCount = ping.summary?.down ?? 0; - const upCount = ping.summary?.up ?? 0; - const configId = ping.config_id; - const monitorQueryId = ping.monitor.id; - - const meta = { - ping, - configId, - monitorQueryId, - locationId: monLocation, - timestamp: ping['@timestamp'], - }; + if (locationSummary) { + const { ping } = locationSummary; + const downCount = ping.summary?.down ?? 0; + const upCount = ping.summary?.up ?? 0; + const configId = ping.config_id; + const monitorQueryId = ping.monitor.id; - if (downCount > 0) { - down += 1; - downConfigs[`${configId}-${monLocation}`] = { - ...meta, - status: 'down', - }; - } else if (upCount > 0) { - up += 1; - upConfigs[`${configId}-${monLocation}`] = { - ...meta, - status: 'up', - }; - } - const monitorsMissingData = monitorsWithoutData.get(monitorQueryId) || []; - monitorsWithoutData.set( - monitorQueryId, - monitorsMissingData?.filter((loc) => loc !== monLocation) - ); - if (!monitorsWithoutData.get(monitorQueryId)?.length) { - monitorsWithoutData.delete(monitorQueryId); - } + const meta = { + ping, + configId, + monitorQueryId, + locationId: monLocation, + timestamp: ping['@timestamp'], + }; + + if (downCount > 0) { + down += 1; + downConfigs[`${configId}-${monLocation}`] = { + ...meta, + status: 'down', + }; + } else if (upCount > 0) { + up += 1; + upConfigs[`${configId}-${monLocation}`] = { + ...meta, + status: 'up', + }; + } + const monitorsMissingData = monitorsWithoutData.get(monitorQueryId) || []; + monitorsWithoutData.set( + monitorQueryId, + monitorsMissingData?.filter((loc) => loc !== monLocation) + ); + if (!monitorsWithoutData.get(monitorQueryId)?.length) { + monitorsWithoutData.delete(monitorQueryId); } - }); + } }); - }, - { concurrency: 5 } - ); + }); + }); // identify the remaining monitors without data, to determine pending monitors for (const [queryId, locs] of monitorsWithoutData) { diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.test.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.test.ts index c850267245b22..cca1e8141f3c9 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.test.ts @@ -108,108 +108,111 @@ describe('current status route', () => { describe('queryMonitorStatus', () => { it('parses expected agg fields', async () => { const { esClient, syntheticsEsClient } = getUptimeESMockClient(); - esClient.search.mockResponseOnce( - getEsResponse([ - { - key: 'id1', - location: { - buckets: [ - { - key: 'Asia/Pacific - Japan', - status: { - hits: { - hits: [ - { - _source: { - '@timestamp': '2022-09-15T16:08:16.724Z', - monitor: { - status: 'up', - id: 'id1', - }, - summary: { - up: 1, - down: 0, - }, - config_id: 'id1', - observer: { - geo: { - name: 'Asia/Pacific - Japan', + esClient.msearch.mockResponseOnce({ + responses: [ + getEsResponse([ + { + key: 'id1', + location: { + buckets: [ + { + key: 'Asia/Pacific - Japan', + status: { + hits: { + hits: [ + { + _source: { + '@timestamp': '2022-09-15T16:08:16.724Z', + monitor: { + status: 'up', + id: 'id1', + }, + summary: { + up: 1, + down: 0, + }, + config_id: 'id1', + observer: { + geo: { + name: 'Asia/Pacific - Japan', + }, }, }, }, - }, - ], + ], + }, }, }, - }, - ], + ], + }, }, - }, - { - key: 'id2', - location: { - buckets: [ - { - key: 'Asia/Pacific - Japan', - status: { - hits: { - hits: [ - { - _source: { - '@timestamp': '2022-09-15T16:09:16.724Z', - monitor: { - status: 'up', - id: 'id2', - }, - summary: { - up: 1, - down: 0, - }, - config_id: 'id2', - observer: { - geo: { - name: 'Asia/Pacific - Japan', + { + key: 'id2', + location: { + buckets: [ + { + key: 'Asia/Pacific - Japan', + status: { + hits: { + hits: [ + { + _source: { + '@timestamp': '2022-09-15T16:09:16.724Z', + monitor: { + status: 'up', + id: 'id2', + }, + summary: { + up: 1, + down: 0, + }, + config_id: 'id2', + observer: { + geo: { + name: 'Asia/Pacific - Japan', + }, }, }, }, - }, - ], + ], + }, }, }, - }, - { - key: 'Europe - Germany', - status: { - hits: { - hits: [ - { - _source: { - '@timestamp': '2022-09-15T16:19:16.724Z', - monitor: { - status: 'down', - id: 'id2', - }, - summary: { - down: 1, - up: 0, - }, - config_id: 'id2', - observer: { - geo: { - name: 'Europe - Germany', + { + key: 'Europe - Germany', + status: { + hits: { + hits: [ + { + _source: { + '@timestamp': '2022-09-15T16:19:16.724Z', + monitor: { + status: 'down', + id: 'id2', + }, + summary: { + down: 1, + up: 0, + }, + config_id: 'id2', + observer: { + geo: { + name: 'Europe - Germany', + }, }, }, }, - }, - ], + ], + }, }, }, - }, - ], + ], + }, }, - }, - ]) - ); + ]), + ], + took: 605, + }); expect( await queryMonitorStatus( syntheticsEsClient, @@ -261,108 +264,111 @@ describe('current status route', () => { it('handles limits with multiple requests', async () => { const { esClient, syntheticsEsClient } = getUptimeESMockClient(); - esClient.search.mockResponseOnce( - getEsResponse([ - { - key: 'id1', - location: { - buckets: [ - { - key: 'Asia/Pacific - Japan', - status: { - hits: { - hits: [ - { - _source: { - '@timestamp': '2022-09-15T16:08:16.724Z', - monitor: { - status: 'up', - id: 'id1', - }, - summary: { - up: 1, - down: 0, - }, - config_id: 'id1', - observer: { - geo: { - name: 'Asia/Pacific - Japan', + esClient.msearch.mockResponseOnce({ + responses: [ + getEsResponse([ + { + key: 'id1', + location: { + buckets: [ + { + key: 'Asia/Pacific - Japan', + status: { + hits: { + hits: [ + { + _source: { + '@timestamp': '2022-09-15T16:08:16.724Z', + monitor: { + status: 'up', + id: 'id1', + }, + summary: { + up: 1, + down: 0, + }, + config_id: 'id1', + observer: { + geo: { + name: 'Asia/Pacific - Japan', + }, }, }, }, - }, - ], + ], + }, }, }, - }, - ], + ], + }, }, - }, - { - key: 'id2', - location: { - buckets: [ - { - key: 'Asia/Pacific - Japan', - status: { - hits: { - hits: [ - { - _source: { - '@timestamp': '2022-09-15T16:09:16.724Z', - monitor: { - status: 'up', - id: 'id2', - }, - summary: { - up: 1, - down: 0, - }, - config_id: 'id2', - observer: { - geo: { - name: 'Asia/Pacific - Japan', + { + key: 'id2', + location: { + buckets: [ + { + key: 'Asia/Pacific - Japan', + status: { + hits: { + hits: [ + { + _source: { + '@timestamp': '2022-09-15T16:09:16.724Z', + monitor: { + status: 'up', + id: 'id2', + }, + summary: { + up: 1, + down: 0, + }, + config_id: 'id2', + observer: { + geo: { + name: 'Asia/Pacific - Japan', + }, }, }, }, - }, - ], + ], + }, }, }, - }, - { - key: 'Europe - Germany', - status: { - hits: { - hits: [ - { - _source: { - '@timestamp': '2022-09-15T16:19:16.724Z', - monitor: { - status: 'down', - id: 'id2', - }, - summary: { - up: 0, - down: 1, - }, - config_id: 'id2', - observer: { - geo: { - name: 'Europe - Germany', + { + key: 'Europe - Germany', + status: { + hits: { + hits: [ + { + _source: { + '@timestamp': '2022-09-15T16:19:16.724Z', + monitor: { + status: 'down', + id: 'id2', + }, + summary: { + up: 0, + down: 1, + }, + config_id: 'id2', + observer: { + geo: { + name: 'Europe - Germany', + }, }, }, }, - }, - ], + ], + }, }, }, - }, - ], + ], + }, }, - }, - ]) - ); + ]), + ], + took: 605, + }); /** * By passing the function a location count of 10k, it forces the query to paginate once, @@ -422,122 +428,125 @@ describe('current status route', () => { }, pendingConfigs: {}, }); - expect(esClient.search).toHaveBeenCalledTimes(2); + expect(esClient.msearch).toHaveBeenCalledTimes(1); // These assertions are to ensure that we are paginating through the IDs we use for filtering expect( // @ts-expect-error mock search is not lining up with expected type - esClient.search.mock.calls[0][0].body.query.bool.filter[2].terms['monitor.id'] + esClient.msearch.mock.calls[0][0].searches[1].query.bool.filter[2].terms['monitor.id'] ).toEqual(['id1']); expect( // @ts-expect-error mock search is not lining up with expected type - esClient.search.mock.calls[1][0].body.query.bool.filter[2].terms['monitor.id'] + esClient.msearch.mock.calls[0][0].searches[3].query.bool.filter[2].terms['monitor.id'] ).toEqual(['id2']); }); it('handles pending configs', async () => { const { esClient, syntheticsEsClient } = getUptimeESMockClient(); - esClient.search.mockResponseOnce( - getEsResponse([ - { - key: 'id1', - location: { - buckets: [ - { - key: 'Asia/Pacific - Japan', - status: { - hits: { - hits: [ - { - _source: { - '@timestamp': '2022-09-15T16:08:16.724Z', - monitor: { - status: 'up', - id: 'id1', - }, - summary: { - up: 1, - down: 0, - }, - config_id: 'id1', - observer: { - geo: { - name: 'Asia/Pacific - Japan', + esClient.msearch.mockResponseOnce({ + responses: [ + getEsResponse([ + { + key: 'id1', + location: { + buckets: [ + { + key: 'Asia/Pacific - Japan', + status: { + hits: { + hits: [ + { + _source: { + '@timestamp': '2022-09-15T16:08:16.724Z', + monitor: { + status: 'up', + id: 'id1', + }, + summary: { + up: 1, + down: 0, + }, + config_id: 'id1', + observer: { + geo: { + name: 'Asia/Pacific - Japan', + }, }, }, }, - }, - ], + ], + }, }, }, - }, - ], + ], + }, }, - }, - { - key: 'id2', - location: { - buckets: [ - { - key: 'Asia/Pacific - Japan', - status: { - hits: { - hits: [ - { - _source: { - '@timestamp': '2022-09-15T16:09:16.724Z', - monitor: { - status: 'up', - id: 'id2', - }, - summary: { - up: 1, - down: 0, - }, - config_id: 'id2', - observer: { - geo: { - name: 'Asia/Pacific - Japan', + { + key: 'id2', + location: { + buckets: [ + { + key: 'Asia/Pacific - Japan', + status: { + hits: { + hits: [ + { + _source: { + '@timestamp': '2022-09-15T16:09:16.724Z', + monitor: { + status: 'up', + id: 'id2', + }, + summary: { + up: 1, + down: 0, + }, + config_id: 'id2', + observer: { + geo: { + name: 'Asia/Pacific - Japan', + }, }, }, }, - }, - ], + ], + }, }, }, - }, - { - key: 'Europe - Germany', - status: { - hits: { - hits: [ - { - _source: { - '@timestamp': '2022-09-15T16:19:16.724Z', - monitor: { - status: 'down', - id: 'id2', - }, - summary: { - down: 1, - up: 0, - }, - config_id: 'id2', - observer: { - geo: { - name: 'Europe - Germany', + { + key: 'Europe - Germany', + status: { + hits: { + hits: [ + { + _source: { + '@timestamp': '2022-09-15T16:19:16.724Z', + monitor: { + status: 'down', + id: 'id2', + }, + summary: { + down: 1, + up: 0, + }, + config_id: 'id2', + observer: { + geo: { + name: 'Europe - Germany', + }, }, }, }, - }, - ], + ], + }, }, }, - }, - ], + ], + }, }, - }, - ]) - ); + ]), + ], + took: 605, + }); expect( await queryMonitorStatus( syntheticsEsClient, @@ -668,108 +677,111 @@ describe('current status route', () => { } as unknown as SavedObjectsFindResult, ]); const { esClient, syntheticsEsClient } = getUptimeESMockClient(); - esClient.search.mockResponseOnce( - getEsResponse([ - { - key: 'id1', - location: { - buckets: [ - { - key: 'Asia/Pacific - Japan', - status: { - hits: { - hits: [ - { - _source: { - '@timestamp': '2022-09-15T16:08:16.724Z', - monitor: { - status: 'up', - id: 'id1', - }, - summary: { - up: 1, - down: 0, - }, - config_id: 'id1', - observer: { - geo: { - name: 'Asia/Pacific - Japan', + esClient.msearch.mockResponseOnce({ + responses: [ + getEsResponse([ + { + key: 'id1', + location: { + buckets: [ + { + key: 'Asia/Pacific - Japan', + status: { + hits: { + hits: [ + { + _source: { + '@timestamp': '2022-09-15T16:08:16.724Z', + monitor: { + status: 'up', + id: 'id1', + }, + summary: { + up: 1, + down: 0, + }, + config_id: 'id1', + observer: { + geo: { + name: 'Asia/Pacific - Japan', + }, }, }, }, - }, - ], + ], + }, }, }, - }, - ], + ], + }, }, - }, - { - key: 'id2', - location: { - buckets: [ - { - key: 'Asia/Pacific - Japan', - status: { - hits: { - hits: [ - { - _source: { - '@timestamp': '2022-09-15T16:09:16.724Z', - monitor: { - status: 'up', - id: 'id2', - }, - summary: { - up: 1, - down: 0, - }, - config_id: 'id2', - observer: { - geo: { - name: 'Asia/Pacific - Japan', + { + key: 'id2', + location: { + buckets: [ + { + key: 'Asia/Pacific - Japan', + status: { + hits: { + hits: [ + { + _source: { + '@timestamp': '2022-09-15T16:09:16.724Z', + monitor: { + status: 'up', + id: 'id2', + }, + summary: { + up: 1, + down: 0, + }, + config_id: 'id2', + observer: { + geo: { + name: 'Asia/Pacific - Japan', + }, }, }, }, - }, - ], + ], + }, }, }, - }, - { - key: 'Europe - Germany', - status: { - hits: { - hits: [ - { - _source: { - '@timestamp': '2022-09-15T16:19:16.724Z', - monitor: { - status: 'down', - id: 'id2', - }, - summary: { - down: 1, - up: 0, - }, - config_id: 'id2', - observer: { - geo: { - name: 'Europe - Germany', + { + key: 'Europe - Germany', + status: { + hits: { + hits: [ + { + _source: { + '@timestamp': '2022-09-15T16:19:16.724Z', + monitor: { + status: 'down', + id: 'id2', + }, + summary: { + down: 1, + up: 0, + }, + config_id: 'id2', + observer: { + geo: { + name: 'Europe - Germany', + }, }, }, }, - }, - ], + ], + }, }, }, - }, - ], + ], + }, }, - }, - ]) - ); + ]), + ], + took: 605, + }); const result = await getStatus( { syntheticsEsClient, @@ -834,7 +846,7 @@ describe('current status route', () => { } as unknown as SavedObjectsFindResult, ]); const { esClient, syntheticsEsClient } = getUptimeESMockClient(); - esClient.search.mockResponseOnce(getEsResponse([])); + esClient.msearch.mockResponseOnce({ responses: [getEsResponse([])], took: 605 }); expect( await getStatus( { From 8627a57d6f2b54dd4c21284d5777a045e95fb1b0 Mon Sep 17 00:00:00 2001 From: "Eyo O. Eyo" <7893459+eokoneyo@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:46:24 +0200 Subject: [PATCH 24/99] prefer attribute selector for selecting element ids (#191632) ## Summary This PR fixes an error that was discovered ahead of the react 18 upgrade(https://github.com/elastic/kibana/issues/138222). Why are we concerned about this? Whilst `useId` isn't directly used in our codebase, it is utilized by EUI's `useGeneratedHtmlId` hook, see https://github.com/elastic/eui/blob/v95.8.0/packages/eui/src/services/accessibility/html_id_generator.ts#L73-L74, the useId hook returns a string that is bounded by colons; if passed to `document.querySelector` as an ID selector, they would cause errors (see https://github.com/facebook/react/issues/26839). As a result, instances where these IDs are being used with `querySelector` have been modified to instead use an attribute selector equivalent to the corresponding ID selector. --------- Co-authored-by: Elastic Machine --- .../src/user_profiles_popover.test.tsx | 4 ++-- .../src/user_profiles_popover.tsx | 2 +- packages/shared-ux/modal/tabbed/src/tabbed_modal.tsx | 6 +++--- .../public/dataview_picker/change_dataview.tsx | 2 +- .../public/components/normalization_menu/index.tsx | 2 +- .../filter_by_assignees_popover.tsx | 2 +- .../flyout/document_details/right/components/assignees.tsx | 2 +- .../components/console_argument_selectors/file_selector.tsx | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/kbn-user-profile-components/src/user_profiles_popover.test.tsx b/packages/kbn-user-profile-components/src/user_profiles_popover.test.tsx index c2b36c39f6955..222567cb83feb 100644 --- a/packages/kbn-user-profile-components/src/user_profiles_popover.test.tsx +++ b/packages/kbn-user-profile-components/src/user_profiles_popover.test.tsx @@ -80,7 +80,7 @@ describe('UserProfilesPopover', () => { closePopover={[MockFunction]} display="inline-block" hasArrow={true} - initialFocus="#searchInput_generated-id" + initialFocus="[id=\\"searchInput_generated-id\\"]" isOpen={false} ownFocus={true} panelPaddingSize="none" @@ -140,7 +140,7 @@ describe('UserProfilesPopover', () => { /> ); - expect(wrapper.find('EuiPopover').prop('initialFocus')).toBe('#searchInput_generated-id'); + expect(wrapper.find('EuiPopover').prop('initialFocus')).toBe('[id="searchInput_generated-id"]'); expect(wrapper.find('UserProfilesSelectable').prop('searchInputId')).toBe( 'searchInput_generated-id' ); diff --git a/packages/kbn-user-profile-components/src/user_profiles_popover.tsx b/packages/kbn-user-profile-components/src/user_profiles_popover.tsx index 69558a058a368..5e4134d73cdb3 100644 --- a/packages/kbn-user-profile-components/src/user_profiles_popover.tsx +++ b/packages/kbn-user-profile-components/src/user_profiles_popover.tsx @@ -45,7 +45,7 @@ export const UserProfilesPopover =
diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/use_virtual_search_results.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/use_virtual_search_results.ts index 602a2d57d8f51..09dd2faf10152 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/use_virtual_search_results.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/use_virtual_search_results.ts @@ -6,14 +6,48 @@ */ import { i18n } from '@kbn/i18n'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { useHistory } from 'react-router-dom'; +import { reactRouterNavigate, useKibana } from '@kbn/kibana-react-plugin/public'; import { CustomCard } from '../packages_list/types'; +import { ObservabilityOnboardingAppServices } from '../..'; export function useVirtualSearchResults(): CustomCard[] { const { - services: { application }, - } = useKibana(); + services: { + application, + context: { isCloud }, + }, + } = useKibana(); + + const history = useHistory(); + const { href: firehoseUrl } = reactRouterNavigate(history, `/firehose/${location.search}`); const getUrlForApp = application?.getUrlForApp; + const firehoseQuickstartCard: CustomCard = { + id: 'firehose-quick-start', + type: 'virtual', + title: i18n.translate('xpack.observability_onboarding.packageList.uploadFileTitle', { + defaultMessage: 'AWS Firehose', + }), + release: 'preview', + description: i18n.translate( + 'xpack.observability_onboarding.packageList.uploadFileDescription', + { + defaultMessage: 'Collect logs and metrics from Amazon Web Services (AWS).', + } + ), + name: 'firehose-quick-start', + categories: [], + icons: [ + { + type: 'svg', + src: 'https://epr.elastic.co/package/awsfirehose/1.1.0/img/logo_firehose.svg', + }, + ], + url: firehoseUrl, + version: '', + integration: '', + isCollectionCard: false, + }; return [ { @@ -42,5 +76,11 @@ export function useVirtualSearchResults(): CustomCard[] { integration: '', isCollectionCard: false, }, + /** + * The new Firehose card should only be visible on Cloud + * as Firehose integration requires additional proxy, + * which is not available for on-prem customers. + */ + ...(isCloud ? [firehoseQuickstartCard] : []), ]; } diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/index.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/index.tsx index 27b5c1f5dc3b4..aa928168d2719 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/index.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/index.tsx @@ -38,6 +38,7 @@ interface Props { * When enabled, custom and integration cards are joined into a single list. */ joinCardLists?: boolean; + excludePackageIdList?: string[]; onLoaded?: () => void; } @@ -58,6 +59,7 @@ const PackageListGridWrapper = ({ flowCategory, flowSearch, joinCardLists = false, + excludePackageIdList = [], onLoaded, }: WrapperProps) => { const customMargin = useCustomMargin(); @@ -68,6 +70,7 @@ const PackageListGridWrapper = ({ const list: IntegrationCardItem[] = useIntegrationCardList( filteredCards, selectedCategory, + excludePackageIdList, customCards, flowCategory, flowSearch, diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/use_integration_card_list.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/use_integration_card_list.ts index baf6bf9dd46d0..d2edc9555fb31 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/use_integration_card_list.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/use_integration_card_list.ts @@ -80,10 +80,12 @@ function useFilteredCards( rewriteUrl: (card: IntegrationCardItem) => IntegrationCardItem, integrationsList: IntegrationCardItem[], selectedCategory: string[], + excludePackageIdList: string[], customCards?: CustomCard[] ) { return useMemo(() => { const integrationCards = integrationsList + .filter((card) => !excludePackageIdList.includes(card.id)) .filter((card) => card.categories.some((category) => selectedCategory.includes(category))) .map(rewriteUrl) .map(toCustomCard); @@ -99,7 +101,7 @@ function useFilteredCards( ), integrationCards, }; - }, [integrationsList, customCards, selectedCategory, rewriteUrl]); + }, [integrationsList, rewriteUrl, customCards, excludePackageIdList, selectedCategory]); } /** @@ -113,6 +115,7 @@ function useFilteredCards( export function useIntegrationCardList( integrationsList: IntegrationCardItem[], selectedCategory: string[], + excludePackageIdList: string[], customCards?: CustomCard[], flowCategory?: string | null, flowSearch?: string, @@ -123,6 +126,7 @@ export function useIntegrationCardList( rewriteUrl, integrationsList, selectedCategory, + excludePackageIdList, customCards ); diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/utils.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/utils.ts index 262f2f8dee709..ea5c992bab5b4 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/utils.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/utils.ts @@ -7,7 +7,11 @@ import { IntegrationCardItem } from '@kbn/fleet-plugin/public'; -export const QUICKSTART_FLOWS = ['auto-detect-logs-virtual', 'kubernetes-quick-start']; +export const QUICKSTART_FLOWS = [ + 'auto-detect-logs-virtual', + 'kubernetes-quick-start', + 'firehose-quick-start', +]; export const toCustomCard = (card: IntegrationCardItem) => ({ ...card, diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/firehose.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/firehose.tsx new file mode 100644 index 0000000000000..638d931997ec3 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/firehose.tsx @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { FirehosePanel } from '../quickstart_flows/firehose'; +import { PageTemplate } from './template'; +import { CustomHeader } from '../header'; + +export const FirehosePage = () => ( + + } + > + + +); diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/index.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/index.ts index acee895fe5ac4..cd4b821f3cc0d 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/index.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/index.ts @@ -11,3 +11,4 @@ export { KubernetesPage } from './kubernetes'; export { LandingPage } from './landing'; export { OtelLogsPage } from './otel_logs'; export { SystemLogsPage } from './system_logs'; +export { FirehosePage } from './firehose'; diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/auto_detect/auto_detect_panel.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/auto_detect/auto_detect_panel.tsx index 1265156d11818..c0bdb89609412 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/auto_detect/auto_detect_panel.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/auto_detect/auto_detect_panel.tsx @@ -24,6 +24,8 @@ import { type SingleDatasetLocatorParams, SINGLE_DATASET_LOCATOR_ID, } from '@kbn/deeplinks-observability/locators'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; import { getAutoDetectCommand } from './get_auto_detect_command'; import { DASHBOARDS, useOnboardingFlow } from './use_onboarding_flow'; import { ProgressIndicator } from '../shared/progress_indicator'; @@ -34,12 +36,16 @@ import { LocatorButtonEmpty } from '../shared/locator_button_empty'; import { GetStartedPanel } from '../shared/get_started_panel'; import { isSupportedLogo, LogoIcon } from '../../shared/logo_icon'; import { FeedbackButtons } from '../shared/feedback_buttons'; +import { ObservabilityOnboardingContextValue } from '../../../plugin'; import { useAutoDetectTelemetry } from './use_auto_detect_telemetry'; export const AutoDetectPanel: FunctionComponent = () => { const { status, data, error, refetch, installedIntegrations } = useOnboardingFlow(); const command = data ? getAutoDetectCommand(data) : undefined; const accordionId = useGeneratedHtmlId({ prefix: 'accordion' }); + const { + services: { share }, + } = useKibana(); useAutoDetectTelemetry( status, @@ -61,6 +67,7 @@ export const AutoDetectPanel: FunctionComponent = () => { const customIntegrations = installedIntegrations.filter( (integration) => integration.installSource === 'custom' ); + const dashboardLocator = share.url.locators.get(DASHBOARD_APP_LOCATOR); return ( @@ -173,10 +180,14 @@ export const AutoDetectPanel: FunctionComponent = () => { integration={integration.pkgName} newTab isLoading={status !== 'dataReceived'} - dashboardLinks={integration.kibanaAssets + actionLinks={integration.kibanaAssets .filter((asset) => asset.type === 'dashboard') .map((asset) => { const dashboard = DASHBOARDS[asset.id as keyof typeof DASHBOARDS]; + const href = + dashboardLocator?.getRedirectUrl({ + dashboardId: asset.id, + }) ?? ''; return { id: asset.id, @@ -210,6 +221,7 @@ export const AutoDetectPanel: FunctionComponent = () => { defaultMessage: 'Explore logs data', } ), + href, }; })} /> diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/create_stack_command_snippet.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/create_stack_command_snippet.tsx new file mode 100644 index 0000000000000..774f02c23a902 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/create_stack_command_snippet.tsx @@ -0,0 +1,105 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + EuiAccordion, + EuiCodeBlock, + EuiLink, + EuiSpacer, + EuiText, + useGeneratedHtmlId, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; +import { + FIREHOSE_CLOUDFORMATION_STACK_NAME, + FIREHOSE_LOGS_STREAM_NAME, + FIREHOSE_METRICS_STREAM_NAME, +} from '../../../../common/aws_firehose'; +import { CopyToClipboardButton } from '../shared/copy_to_clipboard_button'; +import { buildCreateStackCommand, buildStackStatusCommand } from './utils'; + +interface Props { + encodedApiKey: string; + onboardingId: string; + elasticsearchUrl: string; + templateUrl: string; + isCopyPrimaryAction: boolean; +} + +export function CreateStackCommandSnippet({ + encodedApiKey, + elasticsearchUrl, + templateUrl, + isCopyPrimaryAction, +}: Props) { + const stackStatusAccordionId = useGeneratedHtmlId({ prefix: 'stackStatusAccordion' }); + const createStackCommand = buildCreateStackCommand({ + templateUrl, + stackName: FIREHOSE_CLOUDFORMATION_STACK_NAME, + logsStreamName: FIREHOSE_LOGS_STREAM_NAME, + metricsStreamName: FIREHOSE_METRICS_STREAM_NAME, + encodedApiKey, + elasticsearchUrl, + }); + const stackStatusCommand = buildStackStatusCommand({ + stackName: FIREHOSE_CLOUDFORMATION_STACK_NAME, + }); + + return ( + <> + +

+ + {i18n.translate( + 'xpack.observability_onboarding.firehosePanel.awsCLIInstallGuideLinkLabel', + { defaultMessage: 'AWS CLI' } + )} + + ), + }} + /> +

+
+ + + + + {createStackCommand} + + + + + + + + + + + + {stackStatusCommand} + + + + ); +} diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/index.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/index.tsx new file mode 100644 index 0000000000000..520171c835808 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/index.tsx @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState } from 'react'; +import { + EuiPanel, + EuiSkeletonRectangle, + EuiSkeletonText, + EuiSpacer, + EuiSteps, + EuiStepStatus, +} from '@elastic/eui'; +import useEvent from 'react-use/lib/useEvent'; +import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher'; +import { EmptyPrompt } from '../shared/empty_prompt'; +import { CreateStackCommandSnippet } from './create_stack_command_snippet'; +import { VisualizeData } from './visualize_data'; + +export function FirehosePanel() { + const [windowLostFocus, setWindowLostFocus] = useState(false); + const { data, status, error, refetch } = useFetcher( + (callApi) => { + return callApi('POST /internal/observability_onboarding/firehose/flow'); + }, + [], + { showToastOnError: false } + ); + + useEvent('blur', () => setWindowLostFocus(true), window); + + if (error !== undefined) { + return ; + } + + const isVisualizeStepActive = + status === FETCH_STATUS.SUCCESS && data !== undefined && windowLostFocus; + + const steps = [ + { + title: 'Create a Firehose delivery stream and ingest CloudWatch logs', + children: ( + <> + {status !== FETCH_STATUS.SUCCESS && ( + <> + + + + + )} + {status === FETCH_STATUS.SUCCESS && data !== undefined && ( + + )} + + ), + }, + { + title: 'Visualize your data', + status: (isVisualizeStepActive ? 'current' : 'incomplete') as EuiStepStatus, + children: isVisualizeStepActive && , + }, + ]; + + return ( + + + + ); +} diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/use_aws_service_get_started_list.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/use_aws_service_get_started_list.ts new file mode 100644 index 0000000000000..2aa08f7a6bed9 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/use_aws_service_get_started_list.ts @@ -0,0 +1,368 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useCallback, useMemo } from 'react'; +import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; +import { SINGLE_DATASET_LOCATOR_ID } from '@kbn/deeplinks-observability'; +import { i18n } from '@kbn/i18n'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { DISCOVER_APP_LOCATOR } from '@kbn/discover-plugin/common'; +import { AWSIndexName } from '../../../../common/aws_firehose'; +import { ObservabilityOnboardingContextValue } from '../../../plugin'; + +interface AWSServiceGetStartedConfig { + id: string; + indexNameList: AWSIndexName[]; + title: string; + logoURL: string; + previewImage?: string; + actionLinks: Array<{ + id: string; + title: string; + label: string; + href: string; + }>; +} + +export function useAWSServiceGetStartedList(): AWSServiceGetStartedConfig[] { + const { + services: { share }, + } = useKibana(); + const dashboardLocator = share.url.locators.get(DASHBOARD_APP_LOCATOR); + const singleDatasetLocator = share.url.locators.get(SINGLE_DATASET_LOCATOR_ID); + const discoverLocator = share.url.locators.get(DISCOVER_APP_LOCATOR); + + const generateMetricsDashboardActionLink = useCallback( + (dashboardId: string, name?: string) => ({ + id: `dashboard-${dashboardId}`, + title: i18n.translate( + 'xpack.observability_onboarding.firehosePanel.exploreMetricsDataTitle', + { + defaultMessage: 'Overview{name} metrics data with this pre-made dashboard', + values: { name: name ? ` ${name}` : '' }, + } + ), + label: i18n.translate( + 'xpack.observability_onboarding.firehosePanel.exploreMetricsDataLabel', + { + defaultMessage: 'Explore metrics data', + } + ), + href: + dashboardLocator?.getRedirectUrl({ + dashboardId, + }) ?? '', + }), + [dashboardLocator] + ); + + const generateLogsDashboardActionLink = useCallback( + (dashboardId: string) => ({ + id: `dashboard-${dashboardId}`, + title: i18n.translate('xpack.observability_onboarding.firehosePanel.exploreLogsDataTitle', { + defaultMessage: 'Overview your logs data with this pre-made dashboard', + }), + label: i18n.translate('xpack.observability_onboarding.firehosePanel.exploreLogsDataLabel', { + defaultMessage: 'Explore logs data', + }), + href: + dashboardLocator?.getRedirectUrl({ + dashboardId, + }) ?? '', + }), + [dashboardLocator] + ); + + const generateLogsExplorerActionLink = useCallback( + (dataset: string, name: string) => ({ + id: `logs-explorer-${dataset}`, + title: i18n.translate('xpack.observability_onboarding.firehosePanel.exploreDataTitle', { + defaultMessage: 'See {name} data in Logs Explorer', + values: { name }, + }), + label: i18n.translate('xpack.observability_onboarding.firehosePanel.exploreDataLabel', { + defaultMessage: 'Explore', + }), + href: + singleDatasetLocator?.getRedirectUrl({ + integration: 'AWS', + dataset, + }) ?? '', + }), + [singleDatasetLocator] + ); + + const generateMetricsDiscoverActionLink = useCallback( + (namespace: string, name: string) => ({ + id: `logs-explorer-${namespace}`, + title: i18n.translate('xpack.observability_onboarding.firehosePanel.exploreDataTitle', { + defaultMessage: 'See {name} metrics data in Discover', + values: { name }, + }), + label: i18n.translate('xpack.observability_onboarding.firehosePanel.exploreDataLabel', { + defaultMessage: 'Explore', + }), + href: + discoverLocator?.getRedirectUrl({ + dataViewId: `metrics-*`, + query: { + query: `aws.cloudwatch.namespace: ${namespace}`, + language: 'kuery', + }, + }) ?? '', + }), + [discoverLocator] + ); + + return useMemo( + () => [ + { + id: 'vpc-flow', + indexNameList: ['logs-aws.vpcflow'], + title: 'VPC', + logoURL: 'https://epr.elastic.co/package/aws/2.21.0/img/logo_vpcflow.svg', + actionLinks: [generateLogsDashboardActionLink('aws-15503340-4488-11ea-ad63-791a5dc86f10')], + }, + { + id: 'api-gateway', + indexNameList: ['logs-aws.apigateway_logs', 'metrics-aws.apigateway_metrics'], + title: 'API Gateway', + logoURL: 'https://epr.elastic.co/package/aws/2.21.0/img/logo_apigateway.svg', + actionLinks: [ + generateLogsDashboardActionLink('aws-5465f0f0-26e4-11ee-9051-011d57d86fe2'), + generateMetricsDashboardActionLink('aws-bff88770-56d6-11ee-893f-c96e4c6c871e'), + ], + }, + { + id: 'cloudtrail', + indexNameList: ['logs-aws.cloudtrail'], + title: 'CloudTrail', + logoURL: 'https://epr.elastic.co/package/aws/2.21.0/img/logo_cloudtrail.svg', + actionLinks: [generateLogsDashboardActionLink('aws-9c09cd20-7399-11ea-a345-f985c61fe654')], + }, + { + id: 'firewall', + indexNameList: ['logs-aws.firewall_logs'], + title: 'Network Firewall', + logoURL: 'https://epr.elastic.co/package/aws/2.21.0/img/logo_firewall.svg', + actionLinks: [ + generateLogsDashboardActionLink('aws-2ba11b50-4b9d-11ec-8282-5342b8988acc'), + generateMetricsDashboardActionLink('aws-3abffe60-4ba9-11ec-8282-5342b8988acc'), + ], + }, + { + id: 'route53', + indexNameList: ['logs-aws.route53_public_logs', 'logs-aws.route53_resolver_logs'], + title: 'Route53', + logoURL: 'https://epr.elastic.co/package/aws/2.21.0/img/logo_route53.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [ + generateLogsExplorerActionLink('route53_public_logs', 'Route53 public'), + generateLogsExplorerActionLink('route53_resolver_logs', 'Route53 resolver'), + ], + }, + { + id: 'waf', + indexNameList: ['logs-aws.waf'], + title: 'WAF', + logoURL: 'https://epr.elastic.co/package/aws/2.21.0/img/logo_waf.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [generateLogsExplorerActionLink('waf', 'WAF')], + }, + { + id: 'dynamodb', + indexNameList: ['metrics-aws.dynamodb'], + title: 'DynamoDB', + logoURL: 'https://epr.elastic.co/package/aws/2.23.0/img/logo_dynamodb.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [ + generateMetricsDashboardActionLink('aws-68ba7bd0-20b6-11ea-8f72-2f8d21e50b0c'), + ], + }, + { + id: 'ebs', + indexNameList: ['metrics-aws.ebs'], + title: 'EBS', + logoURL: 'https://epr.elastic.co/package/aws/2.23.0/img/logo_ebs.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [ + generateMetricsDashboardActionLink('aws-44ce4680-b7ba-11e9-8349-f15f850c5cd0'), + ], + }, + { + id: 'ec2', + indexNameList: ['metrics-aws.ec2_metrics'], + title: 'EC2', + logoURL: 'https://epr.elastic.co/package/aws/2.23.0/img/logo_ec2.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [ + generateMetricsDashboardActionLink('aws-c5846400-f7fb-11e8-af03-c999c9dea608'), + ], + }, + { + id: 'ecs', + indexNameList: ['metrics-aws.ecs_metrics'], + title: 'ECS', + logoURL: 'https://epr.elastic.co/package/aws/2.23.0/img/logo_ecs.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [generateMetricsDiscoverActionLink('AWS/ECS', 'ECS')], + }, + { + id: 'elb', + indexNameList: ['metrics-aws.elb_metrics'], + title: 'ELB', + logoURL: 'https://epr.elastic.co/package/aws/2.23.0/img/logo_elb.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [ + generateMetricsDashboardActionLink('aws-e74bf320-b3ce-11e9-87a4-078dbbae220d'), + ], + }, + { + id: 'emr', + indexNameList: ['metrics-aws.emr_metrics'], + title: 'EMR', + logoURL: 'https://epr.elastic.co/package/aws/2.23.0/img/logo_emr.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [ + generateMetricsDashboardActionLink('aws-98f85120-0ea4-11ee-9c37-e55025c0278a'), + ], + }, + { + id: 'msk', + indexNameList: ['metrics-aws.kafka_metrics'], + title: 'MSK', + logoURL: 'https://epr.elastic.co/package/aws/2.23.0/img/logo_msk.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [ + generateMetricsDashboardActionLink('aws-62d43b00-d10d-11ee-b93f-db5ae1f208de'), + ], + }, + { + id: 'kinesis', + indexNameList: ['metrics-aws.kinesis'], + title: 'Kinesis Data Stream', + logoURL: 'https://epr.elastic.co/package/aws/2.23.0/img/logo_kinesis.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [ + generateMetricsDashboardActionLink('aws-07d67a60-d872-11eb-8220-c9141cc1b15c'), + ], + }, + { + id: 'lambda', + indexNameList: ['metrics-aws.lambda'], + title: 'Lambda', + logoURL: 'https://epr.elastic.co/package/aws/2.23.0/img/logo_lambda.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [ + generateMetricsDashboardActionLink('aws-7ac8e1d0-28d2-11ea-ba6c-49a884eb104f'), + ], + }, + { + id: 'nat-gateway', + indexNameList: ['metrics-aws.natgateway'], + title: 'NAT Gateway', + logoURL: 'https://epr.elastic.co/package/aws/2.23.0/img/logo_natgateway.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [ + generateMetricsDashboardActionLink('aws-c2b1cbc0-6891-11ea-b0ac-95d4ecb1fecd'), + ], + }, + { + id: 'rds', + indexNameList: ['metrics-aws.rds'], + title: 'RDS', + logoURL: 'https://epr.elastic.co/package/aws/2.23.0/img/logo_rds.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [ + generateMetricsDashboardActionLink('aws-3367c170-921f-11e9-aa19-159bf182e06f'), + ], + }, + { + id: 's3', + indexNameList: [ + 'metrics-aws.s3_storage_lens', + 'metrics-aws.s3_daily_storage', + 'metrics-aws.s3_request', + ], + title: 'S3', + logoURL: 'https://epr.elastic.co/package/aws/2.23.0/img/logo_s3.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [ + generateMetricsDashboardActionLink( + 'aws-80ed1380-41a6-11ec-a605-bff67d9b7872', + 'S3 Storage Lens' + ), + generateMetricsDiscoverActionLink('AWS/S3', 'S3'), + ], + }, + { + id: 'sns', + indexNameList: ['metrics-aws.sns'], + title: 'SNS', + logoURL: 'https://epr.elastic.co/package/aws/2.23.0/img/logo_sns.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [ + generateMetricsDashboardActionLink('aws-d17b1000-17a4-11ea-8e91-03c7047cbb9d'), + ], + }, + { + id: 'sqs', + indexNameList: ['metrics-aws.sqs'], + title: 'SQS', + logoURL: 'https://epr.elastic.co/package/aws/2.23.0/img/logo_sqs.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [ + generateMetricsDashboardActionLink('aws-234aeda0-43b7-11e9-8697-530f39afc6eb'), + ], + }, + { + id: 'transitgateway', + indexNameList: ['metrics-aws.transitgateway'], + title: 'Transit Gateway', + logoURL: 'https://epr.elastic.co/package/aws/2.23.0/img/logo_transitgateway.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [ + generateMetricsDashboardActionLink('aws-0eb5a6a0-694f-11ea-b0ac-95d4ecb1fecd'), + ], + }, + { + id: 'usage', + indexNameList: ['metrics-aws.usage'], + title: 'AWS Usage', + logoURL: 'https://epr.elastic.co/package/aws/2.23.0/img/logo_aws.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [ + generateMetricsDashboardActionLink('aws-917a07b0-178e-11ea-8650-fb606deb5be4'), + ], + }, + { + id: 'vpn', + indexNameList: ['metrics-aws.vpn'], + title: 'VPN', + logoURL: 'https://epr.elastic.co/package/aws/2.23.0/img/logo_vpn.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [ + generateMetricsDashboardActionLink('aws-67c9f900-693e-11ea-b0ac-95d4ecb1fecd'), + ], + }, + { + id: 'firehose', + indexNameList: ['logs-awsfirehose'], + title: 'Uncategorized Firehose Logs', + logoURL: 'https://epr.elastic.co/package/awsfirehose/1.1.0/img/logo_firehose.svg', + previewImage: 'waterfall_screen.svg', + actionLinks: [generateLogsExplorerActionLink('awsfirehose', 'Firehose')], + }, + ], + [ + generateLogsDashboardActionLink, + generateLogsExplorerActionLink, + generateMetricsDashboardActionLink, + generateMetricsDiscoverActionLink, + ] + ); +} diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/utils.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/utils.ts new file mode 100644 index 0000000000000..7fdfe5890830b --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/utils.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export function buildCreateStackCommand({ + templateUrl, + stackName, + logsStreamName, + metricsStreamName, + encodedApiKey, + elasticsearchUrl, +}: { + templateUrl: string; + stackName: string; + logsStreamName: string; + metricsStreamName: string; + encodedApiKey: string; + elasticsearchUrl: string; +}) { + const escapedElasticsearchUrl = elasticsearchUrl.replace(/\//g, '\\/'); + const escapedTemplateUrl = templateUrl.replace(/\//g, '\\/'); + + return ` + aws cloudformation create-stack + --stack-name ${stackName} + --template-url ${escapedTemplateUrl} + --parameters ParameterKey=FirehoseStreamNameForLogs,ParameterValue=${logsStreamName} + ParameterKey=FirehoseStreamNameForMetrics,ParameterValue=${metricsStreamName} + ParameterKey=ElasticEndpointURL,ParameterValue=${escapedElasticsearchUrl} + ParameterKey=ElasticAPIKey,ParameterValue=${encodedApiKey} + --capabilities CAPABILITY_IAM + ` + .trim() + .replace(/\n/g, ' ') + .replace(/\s\s+/g, ' '); +} + +export function buildStackStatusCommand({ stackName }: { stackName: string }) { + return ` + aws cloudformation describe-stacks + --stack-name ${stackName} + --query "Stacks[0].StackStatus" + ` + .trim() + .replace(/\n/g, ' ') + .replace(/\s\s+/g, ' '); +} diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/visualize_data.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/visualize_data.tsx new file mode 100644 index 0000000000000..aee32dee4fa95 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/visualize_data.tsx @@ -0,0 +1,114 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiIcon, EuiSpacer, useEuiTheme, useGeneratedHtmlId } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import useInterval from 'react-use/lib/useInterval'; +import { + FIREHOSE_CLOUDFORMATION_STACK_NAME, + FIREHOSE_LOGS_STREAM_NAME, +} from '../../../../common/aws_firehose'; +import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher'; +import { AccordionWithIcon } from '../shared/accordion_with_icon'; +import { GetStartedPanel } from '../shared/get_started_panel'; +import { ProgressIndicator } from '../shared/progress_indicator'; +import { useAWSServiceGetStartedList } from './use_aws_service_get_started_list'; + +const FETCH_INTERVAL = 2000; +const REQUEST_PENDING_STATUS_LIST = [FETCH_STATUS.LOADING, FETCH_STATUS.NOT_INITIATED]; + +export function VisualizeData() { + const accordionId = useGeneratedHtmlId({ prefix: 'accordion' }); + const { euiTheme } = useEuiTheme(); + const { + data: populatedAWSLogsIndexList, + status, + refetch, + } = useFetcher((callApi) => { + return callApi('GET /internal/observability_onboarding/firehose/has-data', { + params: { + query: { + logsStreamName: FIREHOSE_LOGS_STREAM_NAME, + stackName: FIREHOSE_CLOUDFORMATION_STACK_NAME, + }, + }, + }); + }, []); + const awsServiceGetStartedConfigList = useAWSServiceGetStartedList(); + + useInterval(() => { + if (REQUEST_PENDING_STATUS_LIST.includes(status)) { + return; + } + + refetch(); + }, FETCH_INTERVAL); + + if (populatedAWSLogsIndexList === undefined) { + return null; + } + + return ( + <> + + + + +
+ {awsServiceGetStartedConfigList.map( + ({ id, indexNameList, actionLinks, title, logoURL, previewImage }) => { + const isEnabled = indexNameList.some((indexName) => + populatedAWSLogsIndexList.includes(indexName) + ); + + return ( + } + title={i18n.translate( + 'xpack.observability_onboarding.firehosePanel.awsServiceDataFoundTitle', + { + defaultMessage: '{title}', + values: { title }, + } + )} + extraAction={ + isEnabled ? : null + } + isDisabled={!isEnabled} + css={{ + paddingRight: euiTheme.size.s, + filter: `grayscale(${isEnabled ? 0 : 1})`, + }} + > + + + ); + } + )} +
+ + ); +} diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/data_ingest_status.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/data_ingest_status.tsx index 0afb842ace19f..c3790dc4b11ad 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/data_ingest_status.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/data_ingest_status.tsx @@ -10,6 +10,8 @@ import { EuiLink, EuiSpacer, EuiText } from '@elastic/eui'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; import { StepsProgress, useFlowProgressTelemetry, @@ -17,6 +19,7 @@ import { import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher'; import { ProgressIndicator } from '../shared/progress_indicator'; import { GetStartedPanel } from '../shared/get_started_panel'; +import { ObservabilityOnboardingContextValue } from '../../../plugin'; interface Props { onboardingId: string; @@ -29,6 +32,10 @@ const CLUSTER_OVERVIEW_DASHBOARD_ID = 'kubernetes-f4dc26db-1b53-4ea2-a78b-1bfab8 export function DataIngestStatus({ onboardingId }: Props) { const [progress, setProgress] = useState(undefined); const [checkDataStartTime] = useState(Date.now()); + const { + services: { share }, + } = useKibana(); + const dashboardLocator = share.url.locators.get(DASHBOARD_APP_LOCATOR); const { data, status, refetch } = useFetcher( (callApi) => { @@ -112,7 +119,7 @@ export function DataIngestStatus({ onboardingId }: Props) { integration="kubernetes" newTab={false} isLoading={false} - dashboardLinks={[ + actionLinks={[ { id: CLUSTER_OVERVIEW_DASHBOARD_ID, label: i18n.translate( @@ -127,6 +134,10 @@ export function DataIngestStatus({ onboardingId }: Props) { defaultMessage: 'Overview your Kubernetes cluster with this pre-made dashboard', } ), + href: + dashboardLocator?.getRedirectUrl({ + dashboardId: CLUSTER_OVERVIEW_DASHBOARD_ID, + }) ?? '', }, ]} /> diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/index.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/index.tsx index 6af3e6a9f1817..8411cba6588c8 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/index.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/index.tsx @@ -24,9 +24,13 @@ import { FeedbackButtons } from '../shared/feedback_buttons'; export const KubernetesPanel: React.FC = () => { const [windowLostFocus, setWindowLostFocus] = useState(false); - const { data, status, error, refetch } = useFetcher((callApi) => { - return callApi('POST /internal/observability_onboarding/kubernetes/flow'); - }, []); + const { data, status, error, refetch } = useFetcher( + (callApi) => { + return callApi('POST /internal/observability_onboarding/kubernetes/flow'); + }, + [], + { showToastOnError: false } + ); useEvent('blur', () => setWindowLostFocus(true), window); diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/get_started_panel.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/get_started_panel.tsx index d73555740bed3..f06009dd02edf 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/get_started_panel.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/get_started_panel.tsx @@ -17,31 +17,31 @@ import { import { useKibana } from '@kbn/kibana-react-plugin/public'; import React from 'react'; import { i18n } from '@kbn/i18n'; -import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; import { FormattedMessage } from '@kbn/i18n-react'; import { ObservabilityOnboardingContextValue } from '../../../plugin'; export function GetStartedPanel({ integration, - dashboardLinks, + actionLinks, + previewImage = 'charts_screen.svg', newTab, isLoading, }: { integration: string; newTab: boolean; - dashboardLinks: Array<{ + actionLinks: Array<{ id: string; - label: string; title: string; + label: string; + href: string; }>; + previewImage?: string; isLoading: boolean; }) { const { - services: { http, share }, + services: { http }, } = useKibana(); - const dashboardLocator = share.url.locators.get(DASHBOARD_APP_LOCATOR); - return ( <> @@ -50,7 +50,7 @@ export function GetStartedPanel({ ) : ( - {dashboardLinks.map(({ id, label, title }) => ( + {actionLinks.map(({ id, title, label, href }) => (

{title}

{label} diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/shared/logo_icon.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/shared/logo_icon.tsx index a3da5f171a236..0b49eebb1f94f 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/shared/logo_icon.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/shared/logo_icon.tsx @@ -23,7 +23,8 @@ export type SupportedLogo = | 'nginx' | 'apache' | 'system' - | 'opentelemetry'; + | 'opentelemetry' + | 'firehose'; export function isSupportedLogo(logo: string): logo is SupportedLogo { return [ diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/assets/firehose.svg b/x-pack/plugins/observability_solution/observability_onboarding/public/assets/firehose.svg new file mode 100644 index 0000000000000..53739b79bef77 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/assets/firehose.svg @@ -0,0 +1,12 @@ + + + Icon-Architecture/16/Arch_Amazon-Kinesis-Data-Firehose_16 + + + + + + + + + \ No newline at end of file diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/index.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/index.ts index b84ae734d3859..86f969bb13238 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/index.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/index.ts @@ -30,6 +30,8 @@ export interface ConfigSchema { } export interface AppContext { + isDev: boolean; + isCloud: boolean; isServerless: boolean; stackVersion: string; } diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/plugin.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/plugin.ts index 8f38a38b60fef..514a4fcc94049 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/plugin.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/plugin.ts @@ -81,7 +81,8 @@ export class ObservabilityOnboardingPlugin const { ui: { enabled: isObservabilityOnboardingUiEnabled }, } = config; - + const isServerlessBuild = this.ctx.env.packageInfo.buildFlavor === 'serverless'; + const isDevEnvironment = this.ctx.env.mode.dev; const pluginSetupDeps = plugins; // set xpack.observability_onboarding.ui.enabled: true @@ -112,7 +113,10 @@ export class ObservabilityOnboardingPlugin corePlugins: corePlugins as ObservabilityOnboardingPluginStartDeps, config, context: { - isServerless: Boolean(pluginSetupDeps.cloud?.isServerlessEnabled), + isDev: isDevEnvironment, + isCloud: Boolean(pluginSetupDeps.cloud?.isCloudEnabled), + isServerless: + Boolean(pluginSetupDeps.cloud?.isServerlessEnabled) || isServerlessBuild, stackVersion, }, }); diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/firehose/route.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/firehose/route.ts new file mode 100644 index 0000000000000..64f9a15049fca --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/firehose/route.ts @@ -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 { v4 as uuidv4 } from 'uuid'; +import Boom from '@hapi/boom'; +import * as t from 'io-ts'; +import { termQuery, wildcardQuery } from '@kbn/observability-plugin/server'; +import type { estypes } from '@elastic/elasticsearch'; +import { + AWSIndexName, + AWS_INDEX_NAME_LIST, + FIREHOSE_CLOUDFORMATION_TEMPLATE_URL, +} from '../../../common/aws_firehose'; +import { getFallbackESUrl } from '../../lib/get_fallback_urls'; +import { createObservabilityOnboardingServerRoute } from '../create_observability_onboarding_server_route'; +import { hasLogMonitoringPrivileges } from '../../lib/api_key/has_log_monitoring_privileges'; +import { createShipperApiKey } from '../../lib/api_key/create_shipper_api_key'; + +export interface CreateFirehoseOnboardingFlowRouteResponse { + apiKeyEncoded: string; + onboardingId: string; + elasticsearchUrl: string; + templateUrl: string; +} + +export type HasFirehoseDataRouteResponse = AWSIndexName[]; + +interface DocumentCountPerIndexBucket { + key: string; + doc_count: number; +} + +const createFirehoseOnboardingFlowRoute = createObservabilityOnboardingServerRoute({ + endpoint: 'POST /internal/observability_onboarding/firehose/flow', + options: { tags: [] }, + async handler({ + context, + request, + plugins, + services, + }): Promise { + const { + elasticsearch: { client }, + } = await context.core; + + const hasPrivileges = await hasLogMonitoringPrivileges(client.asCurrentUser); + + if (!hasPrivileges) { + throw Boom.forbidden( + "You don't have enough privileges to start a new onboarding flow. Contact your system administrator to grant you the required privileges." + ); + } + + const fleetPluginStart = await plugins.fleet.start(); + const packageClient = fleetPluginStart.packageService.asScoped(request); + + const [{ encoded: apiKeyEncoded }] = await Promise.all([ + createShipperApiKey(client.asCurrentUser, 'firehose_onboarding'), + packageClient.ensureInstalledPackage({ pkgName: 'awsfirehose' }), + packageClient.ensureInstalledPackage({ pkgName: 'aws' }), + ]); + + const elasticsearchUrlList = plugins.cloud?.setup?.elasticsearchUrl + ? [plugins.cloud?.setup?.elasticsearchUrl] + : await getFallbackESUrl(services.esLegacyConfigService); + + return { + onboardingId: uuidv4(), + apiKeyEncoded, + elasticsearchUrl: elasticsearchUrlList.length > 0 ? elasticsearchUrlList[0] : '', + templateUrl: FIREHOSE_CLOUDFORMATION_TEMPLATE_URL, + }; + }, +}); + +const hasFirehoseDataRoute = createObservabilityOnboardingServerRoute({ + endpoint: 'GET /internal/observability_onboarding/firehose/has-data', + params: t.type({ + query: t.type({ + logsStreamName: t.string, + stackName: t.string, + }), + }), + options: { tags: [] }, + async handler(resources): Promise { + const { logsStreamName, stackName } = resources.params.query; + const { elasticsearch } = await resources.context.core; + const indexPatternList = AWS_INDEX_NAME_LIST.map((index) => `${index}-*`); + + try { + const result = await elasticsearch.client.asCurrentUser.search< + unknown, + Record< + 'documents_per_index', + estypes.AggregationsMultiBucketAggregateBase + > + >({ + index: indexPatternList, + ignore_unavailable: true, + size: 0, + query: { + bool: { + should: [ + ...termQuery('aws.kinesis.name', logsStreamName), + ...wildcardQuery('aws.exporter.arn', stackName), + ], + }, + }, + aggs: { + documents_per_index: { + terms: { + field: '_index', + size: indexPatternList.length, + }, + }, + }, + }); + + const buckets = result.aggregations?.documents_per_index.buckets; + + if (!Array.isArray(buckets)) { + return []; + } + + return AWS_INDEX_NAME_LIST.filter((indexName) => { + return buckets.some((bucket) => bucket.key.includes(indexName) && bucket.doc_count > 0); + }); + } catch (error) { + throw Boom.internal(`Elasticsearch responded with an error. ${error.message}`); + } + }, +}); + +export const firehoseOnboardingRouteRepository = { + ...createFirehoseOnboardingFlowRoute, + ...hasFirehoseDataRoute, +}; diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/index.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/index.ts index e444f2266f18f..947914c66dfb0 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/index.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/index.ts @@ -9,6 +9,7 @@ import { elasticAgentRouteRepository } from './elastic_agent/route'; import { flowRouteRepository } from './flow/route'; import { kubernetesOnboardingRouteRepository } from './kubernetes/route'; import { logsOnboardingRouteRepository } from './logs/route'; +import { firehoseOnboardingRouteRepository } from './firehose/route'; function getTypedObservabilityOnboardingServerRouteRepository() { const repository = { @@ -16,6 +17,7 @@ function getTypedObservabilityOnboardingServerRouteRepository() { ...logsOnboardingRouteRepository, ...elasticAgentRouteRepository, ...kubernetesOnboardingRouteRepository, + ...firehoseOnboardingRouteRepository, }; return repository; diff --git a/x-pack/test_serverless/functional/test_suites/observability/onboarding/firehose.ts b/x-pack/test_serverless/functional/test_suites/observability/onboarding/firehose.ts new file mode 100644 index 0000000000000..313dd001c4f4a --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/observability/onboarding/firehose.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 expect from 'expect'; +import { log, timerange } from '@kbn/apm-synthtrace-client'; +import moment from 'moment'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +const CF_COMMAND_REGEXP = + /aws cloudformation create-stack --stack-name (\S+) --template-url \S+ --parameters ParameterKey=FirehoseStreamNameForLogs,ParameterValue=(\S+) .+? --capabilities CAPABILITY_IAM/; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const PageObjects = getPageObjects(['common', 'svlCommonPage']); + + const browser = getService('browser'); + const testSubjects = getService('testSubjects'); + const synthtrace = getService('svlLogsSynthtraceClient'); + + describe('Onboarding Firehose Quickstart Flow', () => { + before(async () => { + await PageObjects.svlCommonPage.loginAsAdmin(); // Onboarding requires admin role + await PageObjects.common.navigateToUrlWithBrowserHistory( + 'observabilityOnboarding', + '/firehose', + undefined, + { + ensureCurrentUrl: false, // the check sometimes is too slow for the page so it misses the point in time before the app rewrites the URL + } + ); + }); + + after(async () => { + await synthtrace.clean(); + }); + + beforeEach(async () => { + await testSubjects.existOrFail('observabilityOnboardingFirehoseCreateStackCommand'); + }); + + it('shows the correct CloudFormation command snippet', async () => { + await testSubjects.clickWhenNotDisabled('observabilityOnboardingCopyToClipboardButton'); + const copiedCommand = await browser.getClipboardValue(); + + expect(copiedCommand).toMatch(CF_COMMAND_REGEXP); + }); + + it('starts to monitor for incoming data after user leaves the page', async () => { + await browser.execute(`window.dispatchEvent(new Event("blur"))`); + + await testSubjects.isDisplayed('observabilityOnboardingAWSServiceList'); + }); + + it('highlights an AWS service when data is detected', async () => { + const DATASET = 'aws.vpcflow'; + const AWS_SERVICE_ID = 'vpc-flow'; + await testSubjects.clickWhenNotDisabled('observabilityOnboardingCopyToClipboardButton'); + const copiedCommand = await browser.getClipboardValue(); + const [, _stackName, logsStreamName] = copiedCommand.match(CF_COMMAND_REGEXP) ?? []; + + expect(logsStreamName).toBeDefined(); + + await browser.execute(`window.dispatchEvent(new Event("blur"))`); + + // Simulate Firehose stream ingesting log files + const to = new Date().toISOString(); + const count = 1; + await synthtrace.index( + timerange(moment(to).subtract(count, 'minute'), moment(to)) + .interval('1m') + .rate(1) + .generator((timestamp) => { + return log.create().dataset(DATASET).timestamp(timestamp).defaults({ + 'aws.kinesis.name': logsStreamName, + }); + }) + ); + + // Checking that an AWS service item is enabled after data is detected + await testSubjects + .find(`observabilityOnboardingAWSService-${AWS_SERVICE_ID}`) + .then((el) => el.findByTagName('button')) + .then((el) => el.isEnabled()); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/observability/onboarding/index.ts b/x-pack/test_serverless/functional/test_suites/observability/onboarding/index.ts index 604d0fc4dc3ae..3debbc8ab622a 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/onboarding/index.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/onboarding/index.ts @@ -10,5 +10,6 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('Onboarding', function () { loadTestFile(require.resolve('./auto_detect')); + loadTestFile(require.resolve('./firehose')); }); } From b9319a6ad453914c670a486075c0b6557809f9cc Mon Sep 17 00:00:00 2001 From: Milton Hultgren Date: Fri, 6 Sep 2024 11:11:28 +0200 Subject: [PATCH 71/99] [EEM] Migrate to using @kbn/server-route-repository (#191102) Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../src/parse_endpoint.ts | 4 +- x-pack/packages/kbn-entities-schema/oas.yaml | 55 +++++- .../src/rest_spec/create.ts | 2 - .../src/rest_spec/delete.ts | 2 - .../public/lib/entity_client.ts | 62 +++++-- .../entity_manager/public/plugin.ts | 4 +- .../entity_manager/public/types.ts | 23 +-- .../entity_manager/server/index.ts | 8 +- .../entity_manager/server/plugin.ts | 48 +++--- .../create_entity_manager_server_route.ts | 12 ++ .../server/routes/enablement/check.ts | 127 +++++++------- .../server/routes/enablement/disable.ts | 107 ++++++------ .../server/routes/enablement/enable.ts | 156 ++++++++---------- .../server/routes/enablement/index.ts | 16 ++ .../server/routes/entities/create.ts | 79 ++++----- .../server/routes/entities/delete.ts | 62 +++---- .../server/routes/entities/get.ts | 50 +++--- .../server/routes/entities/index.ts | 20 +++ .../server/routes/entities/reset.ts | 117 ++++++------- .../server/routes/entities/update.ts | 121 ++++++-------- .../entity_manager/server/routes/index.ts | 28 +--- .../entity_manager/server/routes/types.ts | 13 +- .../entity_manager/tsconfig.json | 3 + 23 files changed, 580 insertions(+), 539 deletions(-) create mode 100644 x-pack/plugins/observability_solution/entity_manager/server/routes/create_entity_manager_server_route.ts create mode 100644 x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/index.ts create mode 100644 x-pack/plugins/observability_solution/entity_manager/server/routes/entities/index.ts diff --git a/packages/kbn-server-route-repository-utils/src/parse_endpoint.ts b/packages/kbn-server-route-repository-utils/src/parse_endpoint.ts index 93c79cf994f51..aaee430d5d13f 100644 --- a/packages/kbn-server-route-repository-utils/src/parse_endpoint.ts +++ b/packages/kbn-server-route-repository-utils/src/parse_endpoint.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -type Method = 'get' | 'post' | 'put' | 'delete'; +type Method = 'get' | 'post' | 'put' | 'patch' | 'delete'; export function parseEndpoint(endpoint: string) { const parts = endpoint.split(' '); @@ -15,7 +15,7 @@ export function parseEndpoint(endpoint: string) { const pathname = parts[1].trim(); const version = parts[2]?.trim(); - if (!['get', 'post', 'put', 'delete'].includes(method)) { + if (!['get', 'post', 'put', 'patch', 'delete'].includes(method)) { throw new Error(`Endpoint ${endpoint} was not prefixed with a valid HTTP method`); } diff --git a/x-pack/packages/kbn-entities-schema/oas.yaml b/x-pack/packages/kbn-entities-schema/oas.yaml index 35e6eafe6a43a..aff5581a989c8 100644 --- a/x-pack/packages/kbn-entities-schema/oas.yaml +++ b/x-pack/packages/kbn-entities-schema/oas.yaml @@ -8,7 +8,12 @@ components: type: object properties: installOnly: - type: boolean + anyOf: + - type: string + enum: + - "true" + - "false" + - type: boolean default: false additionalProperties: false getEntityDefinitionQuerySchema: @@ -39,7 +44,12 @@ components: type: object properties: deleteData: - type: boolean + anyOf: + - type: string + enum: + - "true" + - "false" + - type: boolean default: false additionalProperties: false entityDefinitionSchema: @@ -393,6 +403,7 @@ paths: application/json: schema: type: object + required: enabled properties: enabled: type: boolean @@ -422,6 +433,7 @@ paths: application/json: schema: type: object + required: success properties: success: type: boolean @@ -447,6 +459,7 @@ paths: application/json: schema: type: object + required: success properties: success: type: boolean @@ -491,7 +504,8 @@ paths: $ref: "#/components/schemas/entityDefinitionSchema" "400": description: The entity definition cannot be installed; see the error for more - details + details but commonly due to validation failures of the definition ID + or metrics format "409": description: An entity definition with this ID already exists delete: @@ -564,4 +578,39 @@ paths: type: boolean running: type: boolean + patch: + description: Update an entity definition. + tags: + - definitions + parameters: + - in: query + name: installOnly + description: If true, the definition transforms will not be started + required: false + schema: + type: boolean + default: false + requestBody: + description: The definition properties to update + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/entityDefinitionUpdateSchema" + responses: + "200": + description: Success + content: + application/json: + schema: + $ref: "#/components/schemas/entityDefinitionSchema" + "400": + description: The entity definition cannot be installed; see the error for more + details + "403": + description: User is not allowed to update the entity definition + "404": + description: The entity definition does not exist + "409": + description: The entity definition is being updated by another request tags: [] diff --git a/x-pack/packages/kbn-entities-schema/src/rest_spec/create.ts b/x-pack/packages/kbn-entities-schema/src/rest_spec/create.ts index c6ee26d3a3d26..dcce87721f908 100644 --- a/x-pack/packages/kbn-entities-schema/src/rest_spec/create.ts +++ b/x-pack/packages/kbn-entities-schema/src/rest_spec/create.ts @@ -11,5 +11,3 @@ import { BooleanFromString } from '@kbn/zod-helpers'; export const createEntityDefinitionQuerySchema = z.object({ installOnly: z.optional(BooleanFromString).default(false), }); - -export type CreateEntityDefinitionQuery = z.infer; diff --git a/x-pack/packages/kbn-entities-schema/src/rest_spec/delete.ts b/x-pack/packages/kbn-entities-schema/src/rest_spec/delete.ts index 0bac10c2be264..14753382f5b7c 100644 --- a/x-pack/packages/kbn-entities-schema/src/rest_spec/delete.ts +++ b/x-pack/packages/kbn-entities-schema/src/rest_spec/delete.ts @@ -15,5 +15,3 @@ export const deleteEntityDefinitionParamsSchema = z.object({ export const deleteEntityDefinitionQuerySchema = z.object({ deleteData: z.optional(BooleanFromString).default(false), }); - -export type DeleteEntityDefinitionQuery = z.infer; diff --git a/x-pack/plugins/observability_solution/entity_manager/public/lib/entity_client.ts b/x-pack/plugins/observability_solution/entity_manager/public/lib/entity_client.ts index 8246ad45583fb..c4a2897cbc474 100644 --- a/x-pack/plugins/observability_solution/entity_manager/public/lib/entity_client.ts +++ b/x-pack/plugins/observability_solution/entity_manager/public/lib/entity_client.ts @@ -5,32 +5,60 @@ * 2.0. */ -import { HttpStart } from '@kbn/core/public'; -import { CreateEntityDefinitionQuery, DeleteEntityDefinitionQuery } from '@kbn/entities-schema'; -import { EntityManagerUnauthorizedError } from './errors'; -import { IEntityClient } from '../types'; +import { CoreSetup, CoreStart } from '@kbn/core/public'; +import { + ClientRequestParamsOf, + RouteRepositoryClient, + createRepositoryClient, + isHttpFetchError, +} from '@kbn/server-route-repository-client'; import { - ManagedEntityEnabledResponse, - EnableManagedEntityResponse, DisableManagedEntityResponse, + EnableManagedEntityResponse, + ManagedEntityEnabledResponse, } from '../../common/types_api'; +import type { EntityManagerRouteRepository } from '../../server'; +import { EntityManagerUnauthorizedError } from './errors'; -export class EntityClient implements IEntityClient { - constructor(private readonly http: HttpStart) {} +type EntityManagerRepositoryClient = RouteRepositoryClient; + +type QueryParamOf = Exclude['query']; + +type DeleteEntityDefinitionQuery = QueryParamOf< + ClientRequestParamsOf< + EntityManagerRouteRepository, + 'DELETE /internal/entities/managed/enablement' + > +>; + +type CreateEntityDefinitionQuery = QueryParamOf< + ClientRequestParamsOf +>; + +export class EntityClient { + public readonly repositoryClient: EntityManagerRepositoryClient; + + constructor(core: CoreStart | CoreSetup) { + this.repositoryClient = createRepositoryClient(core).fetch; + } async isManagedEntityDiscoveryEnabled(): Promise { - return await this.http.get('/internal/entities/managed/enablement'); + return await this.repositoryClient('GET /internal/entities/managed/enablement'); } async enableManagedEntityDiscovery( query?: CreateEntityDefinitionQuery ): Promise { try { - return await this.http.put('/internal/entities/managed/enablement', { - query, + return await this.repositoryClient('PUT /internal/entities/managed/enablement', { + params: { + query: { + installOnly: query?.installOnly, + }, + }, }); } catch (err) { - if (err.body?.statusCode === 403) { + if (isHttpFetchError(err) && err.body?.statusCode === 403) { throw new EntityManagerUnauthorizedError(err.body.message); } throw err; @@ -41,9 +69,15 @@ export class EntityClient implements IEntityClient { query?: DeleteEntityDefinitionQuery ): Promise { try { - return await this.http.delete('/internal/entities/managed/enablement', { query }); + return await this.repositoryClient('DELETE /internal/entities/managed/enablement', { + params: { + query: { + deleteData: query?.deleteData, + }, + }, + }); } catch (err) { - if (err.body?.statusCode === 403) { + if (isHttpFetchError(err) && err.body?.statusCode === 403) { throw new EntityManagerUnauthorizedError(err.body.message); } throw err; diff --git a/x-pack/plugins/observability_solution/entity_manager/public/plugin.ts b/x-pack/plugins/observability_solution/entity_manager/public/plugin.ts index 0de83b4252b62..6d6d56a95b757 100644 --- a/x-pack/plugins/observability_solution/entity_manager/public/plugin.ts +++ b/x-pack/plugins/observability_solution/entity_manager/public/plugin.ts @@ -22,14 +22,14 @@ export class Plugin implements EntityManagerPluginClass { } setup(core: CoreSetup) { - const entityClient = new EntityClient(core.http); + const entityClient = new EntityClient(core); return { entityClient, }; } start(core: CoreStart) { - const entityClient = new EntityClient(core.http); + const entityClient = new EntityClient(core); return { entityClient, }; diff --git a/x-pack/plugins/observability_solution/entity_manager/public/types.ts b/x-pack/plugins/observability_solution/entity_manager/public/types.ts index 518d760ffec74..66499479299dc 100644 --- a/x-pack/plugins/observability_solution/entity_manager/public/types.ts +++ b/x-pack/plugins/observability_solution/entity_manager/public/types.ts @@ -5,30 +5,17 @@ * 2.0. */ import type { Plugin as PluginClass } from '@kbn/core/public'; -import { CreateEntityDefinitionQuery } from '@kbn/entities-schema'; -import { - DisableManagedEntityResponse, - EnableManagedEntityResponse, - ManagedEntityEnabledResponse, -} from '../common/types_api'; +import type { EntityClient } from './lib/entity_client'; export interface EntityManagerPublicPluginSetup { - entityClient: IEntityClient; + entityClient: EntityClient; } export interface EntityManagerPublicPluginStart { - entityClient: IEntityClient; + entityClient: EntityClient; } export type EntityManagerPluginClass = PluginClass< - EntityManagerPublicPluginSetup | undefined, - EntityManagerPublicPluginStart | undefined + EntityManagerPublicPluginSetup, + EntityManagerPublicPluginStart >; - -export interface IEntityClient { - isManagedEntityDiscoveryEnabled: () => Promise; - enableManagedEntityDiscovery: ( - query?: CreateEntityDefinitionQuery - ) => Promise; - disableManagedEntityDiscovery: () => Promise; -} diff --git a/x-pack/plugins/observability_solution/entity_manager/server/index.ts b/x-pack/plugins/observability_solution/entity_manager/server/index.ts index 172b22b588f58..ebb826a500a5a 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/index.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/index.ts @@ -8,8 +8,14 @@ import { PluginInitializerContext } from '@kbn/core-plugins-server'; import { EntityManagerConfig } from '../common/config'; import { EntityManagerServerPluginSetup, EntityManagerServerPluginStart, config } from './plugin'; +import { EntityManagerRouteRepository } from './routes'; -export type { EntityManagerConfig, EntityManagerServerPluginSetup, EntityManagerServerPluginStart }; +export type { + EntityManagerConfig, + EntityManagerServerPluginSetup, + EntityManagerServerPluginStart, + EntityManagerRouteRepository, +}; export { config }; export const plugin = async (context: PluginInitializerContext) => { diff --git a/x-pack/plugins/observability_solution/entity_manager/server/plugin.ts b/x-pack/plugins/observability_solution/entity_manager/server/plugin.ts index d65a2a9e186f3..3adfe5b9167e2 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/plugin.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/plugin.ts @@ -5,29 +5,30 @@ * 2.0. */ -import { firstValueFrom } from 'rxjs'; import { - Plugin, CoreSetup, - RequestHandlerContext, CoreStart, - PluginInitializerContext, - PluginConfigDescriptor, - Logger, KibanaRequest, + Logger, + Plugin, + PluginConfigDescriptor, + PluginInitializerContext, } from '@kbn/core/server'; +import { registerRoutes } from '@kbn/server-route-repository'; +import { firstValueFrom } from 'rxjs'; +import { EntityManagerConfig, configSchema, exposeToBrowserConfig } from '../common/config'; +import { builtInDefinitions } from './lib/entities/built_in'; +import { upgradeBuiltInEntityDefinitions } from './lib/entities/upgrade_entity_definition'; +import { EntityClient } from './lib/entity_client'; import { installEntityManagerTemplates } from './lib/manage_index_templates'; -import { setupRoutes } from './routes'; +import { entityManagerRouteRepository } from './routes'; +import { EntityManagerRouteDependencies } from './routes/types'; +import { EntityDiscoveryApiKeyType, entityDefinition } from './saved_objects'; import { EntityManagerPluginSetupDependencies, EntityManagerPluginStartDependencies, EntityManagerServerSetup, } from './types'; -import { EntityManagerConfig, configSchema, exposeToBrowserConfig } from '../common/config'; -import { entityDefinition, EntityDiscoveryApiKeyType } from './saved_objects'; -import { upgradeBuiltInEntityDefinitions } from './lib/entities/upgrade_entity_definition'; -import { builtInDefinitions } from './lib/entities/built_in'; -import { EntityClient } from './lib/entity_client'; export type EntityManagerServerPluginSetup = ReturnType; export type EntityManagerServerPluginStart = ReturnType; @@ -64,23 +65,24 @@ export class EntityManagerServerPlugin attributesToIncludeInAAD: new Set(['id', 'name']), }); - const router = core.http.createRouter(); - this.server = { config: this.config, logger: this.logger, } as EntityManagerServerSetup; - setupRoutes({ - router, - logger: this.logger, - server: this.server, - getScopedClient: async ({ request }: { request: KibanaRequest }) => { - const [coreStart] = await core.getStartServices(); - const esClient = coreStart.elasticsearch.client.asScoped(request).asCurrentUser; - const soClient = coreStart.savedObjects.getScopedClient(request); - return new EntityClient({ esClient, soClient, logger: this.logger }); + registerRoutes({ + repository: entityManagerRouteRepository, + dependencies: { + server: this.server, + getScopedClient: async ({ request }: { request: KibanaRequest }) => { + const [coreStart] = await core.getStartServices(); + const esClient = coreStart.elasticsearch.client.asScoped(request).asCurrentUser; + const soClient = coreStart.savedObjects.getScopedClient(request); + return new EntityClient({ esClient, soClient, logger: this.logger }); + }, }, + core, + logger: this.logger, }); return {}; diff --git a/x-pack/plugins/observability_solution/entity_manager/server/routes/create_entity_manager_server_route.ts b/x-pack/plugins/observability_solution/entity_manager/server/routes/create_entity_manager_server_route.ts new file mode 100644 index 0000000000000..7afa6dd375520 --- /dev/null +++ b/x-pack/plugins/observability_solution/entity_manager/server/routes/create_entity_manager_server_route.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createServerRouteFactory } from '@kbn/server-route-repository'; +import { EntityManagerRouteHandlerResources } from './types'; + +export const createEntityManagerServerRoute = + createServerRouteFactory(); diff --git a/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/check.ts b/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/check.ts index 8b9b96fe9e4b9..cadd4e1dc4dec 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/check.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/check.ts @@ -6,9 +6,6 @@ */ import semver from 'semver'; -import { RequestHandlerContext } from '@kbn/core/server'; -import { SetupRouteOptions } from '../types'; -import { checkIfEntityDiscoveryAPIKeyIsValid, readEntityDiscoveryAPIKey } from '../../lib/auth'; import { ERROR_API_KEY_NOT_FOUND, ERROR_API_KEY_NOT_VALID, @@ -16,9 +13,11 @@ import { ERROR_DEFINITION_STOPPED, ERROR_PARTIAL_BUILTIN_INSTALLATION, } from '../../../common/errors'; -import { findEntityDefinitions } from '../../lib/entities/find_entity_definition'; +import { checkIfEntityDiscoveryAPIKeyIsValid, readEntityDiscoveryAPIKey } from '../../lib/auth'; import { builtInDefinitions } from '../../lib/entities/built_in'; +import { findEntityDefinitions } from '../../lib/entities/find_entity_definition'; import { getClientsFromAPIKey } from '../../lib/utils'; +import { createEntityManagerServerRoute } from '../create_entity_manager_server_route'; /** * @openapi @@ -34,6 +33,7 @@ import { getClientsFromAPIKey } from '../../lib/utils'; * application/json: * schema: * type: object + * required: enabled * properties: * enabled: * type: boolean @@ -42,77 +42,70 @@ import { getClientsFromAPIKey } from '../../lib/utils'; * type: string * example: api_key_not_found */ -export function checkEntityDiscoveryEnabledRoute({ - router, - server, - logger, -}: SetupRouteOptions) { - router.get( - { - path: '/internal/entities/managed/enablement', - validate: false, - }, - async (context, req, res) => { - try { - logger.debug('reading entity discovery API key from saved object'); - const apiKey = await readEntityDiscoveryAPIKey(server); - - if (apiKey === undefined) { - return res.ok({ body: { enabled: false, reason: ERROR_API_KEY_NOT_FOUND } }); - } +export const checkEntityDiscoveryEnabledRoute = createEntityManagerServerRoute({ + endpoint: 'GET /internal/entities/managed/enablement', + handler: async ({ response, logger, server }) => { + try { + logger.debug('reading entity discovery API key from saved object'); + const apiKey = await readEntityDiscoveryAPIKey(server); - logger.debug('validating existing entity discovery API key'); - const isValid = await checkIfEntityDiscoveryAPIKeyIsValid(server, apiKey); + if (apiKey === undefined) { + return response.ok({ body: { enabled: false, reason: ERROR_API_KEY_NOT_FOUND } }); + } - if (!isValid) { - return res.ok({ body: { enabled: false, reason: ERROR_API_KEY_NOT_VALID } }); - } + logger.debug('validating existing entity discovery API key'); + const isValid = await checkIfEntityDiscoveryAPIKeyIsValid(server, apiKey); - const { esClient, soClient } = getClientsFromAPIKey({ apiKey, server }); + if (!isValid) { + return response.ok({ body: { enabled: false, reason: ERROR_API_KEY_NOT_VALID } }); + } - const entityDiscoveryState = await Promise.all( - builtInDefinitions.map(async (builtInDefinition) => { - const definitions = await findEntityDefinitions({ - esClient, - soClient, - id: builtInDefinition.id, - }); + const { esClient, soClient } = getClientsFromAPIKey({ apiKey, server }); - return { installedDefinition: definitions[0], builtInDefinition }; - }) - ).then((results) => - results.reduce( - (state, { installedDefinition, builtInDefinition }) => { - return { - installed: Boolean(state.installed && installedDefinition?.state.installed), - running: Boolean(state.running && installedDefinition?.state.running), - outdated: - state.outdated || - (installedDefinition && - semver.neq(installedDefinition.version, builtInDefinition.version)), - }; - }, - { installed: true, running: true, outdated: false } - ) - ); + const entityDiscoveryState = await Promise.all( + builtInDefinitions.map(async (builtInDefinition) => { + const definitions = await findEntityDefinitions({ + esClient, + soClient, + id: builtInDefinition.id, + }); - if (!entityDiscoveryState.installed) { - return res.ok({ body: { enabled: false, reason: ERROR_PARTIAL_BUILTIN_INSTALLATION } }); - } + return { installedDefinition: definitions[0], builtInDefinition }; + }) + ).then((results) => + results.reduce( + (state, { installedDefinition, builtInDefinition }) => { + return { + installed: Boolean(state.installed && installedDefinition?.state.installed), + running: Boolean(state.running && installedDefinition?.state.running), + outdated: + state.outdated || + (installedDefinition && + semver.neq(installedDefinition.version, builtInDefinition.version)), + }; + }, + { installed: true, running: true, outdated: false } + ) + ); - if (!entityDiscoveryState.running) { - return res.ok({ body: { enabled: false, reason: ERROR_DEFINITION_STOPPED } }); - } + if (!entityDiscoveryState.installed) { + return response.ok({ + body: { enabled: false, reason: ERROR_PARTIAL_BUILTIN_INSTALLATION }, + }); + } - if (entityDiscoveryState.outdated) { - return res.ok({ body: { enabled: false, reason: ERROR_BUILTIN_UPGRADE_REQUIRED } }); - } + if (!entityDiscoveryState.running) { + return response.ok({ body: { enabled: false, reason: ERROR_DEFINITION_STOPPED } }); + } - return res.ok({ body: { enabled: true } }); - } catch (err) { - logger.error(err); - return res.customError({ statusCode: 500, body: err }); + if (entityDiscoveryState.outdated) { + return response.ok({ body: { enabled: false, reason: ERROR_BUILTIN_UPGRADE_REQUIRED } }); } + + return response.ok({ body: { enabled: true } }); + } catch (err) { + logger.error(err); + return response.customError({ statusCode: 500, body: err }); } - ); -} + }, +}); diff --git a/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/disable.ts b/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/disable.ts index e122f40bd878a..bde68eb85ba9f 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/disable.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/disable.ts @@ -5,13 +5,13 @@ * 2.0. */ -import { RequestHandlerContext } from '@kbn/core/server'; -import { schema } from '@kbn/config-schema'; -import { SetupRouteOptions } from '../types'; +import { z } from '@kbn/zod'; +import { BooleanFromString } from '@kbn/zod-helpers'; import { deleteEntityDiscoveryAPIKey, readEntityDiscoveryAPIKey } from '../../lib/auth'; -import { uninstallBuiltInEntityDefinitions } from '../../lib/entities/uninstall_entity_definition'; import { canDisableEntityDiscovery } from '../../lib/auth/privileges'; +import { uninstallBuiltInEntityDefinitions } from '../../lib/entities/uninstall_entity_definition'; import { EntityDiscoveryApiKeyType } from '../../saved_objects'; +import { createEntityManagerServerRoute } from '../create_entity_manager_server_route'; /** * @openapi @@ -29,72 +29,65 @@ import { EntityDiscoveryApiKeyType } from '../../saved_objects'; * type: boolean * default: false * responses: - * 403: - * description: The current user does not have the required permissions to disable entity discovery * 200: * description: Built-in entity discovery successfully disabled * content: * application/json: * schema: * type: object + * required: success * properties: * success: * type: boolean + * 403: + * description: The current user does not have the required permissions to disable entity discovery */ -export function disableEntityDiscoveryRoute({ - router, - server, - logger, -}: SetupRouteOptions) { - router.delete( - { - path: '/internal/entities/managed/enablement', - validate: { - query: schema.object({ - deleteData: schema.maybe(schema.boolean({ defaultValue: false })), - }), - }, - }, - async (context, req, res) => { - try { - const esClient = (await context.core).elasticsearch.client.asCurrentUser; - const canDisable = await canDisableEntityDiscovery(esClient); - if (!canDisable) { - return res.forbidden({ - body: { - message: - 'Current Kibana user does not have the required permissions to disable entity discovery', - }, - }); - } - - const soClient = (await context.core).savedObjects.getClient({ - includedHiddenTypes: [EntityDiscoveryApiKeyType.name], +export const disableEntityDiscoveryRoute = createEntityManagerServerRoute({ + endpoint: 'DELETE /internal/entities/managed/enablement', + params: z.object({ + query: z.object({ + deleteData: z.optional(BooleanFromString).default(false), + }), + }), + handler: async ({ context, response, params, logger, server }) => { + try { + const esClient = (await context.core).elasticsearch.client.asCurrentUser; + const canDisable = await canDisableEntityDiscovery(esClient); + if (!canDisable) { + return response.forbidden({ + body: { + message: + 'Current Kibana user does not have the required permissions to disable entity discovery', + }, }); + } - await uninstallBuiltInEntityDefinitions({ - soClient, - esClient, - logger, - deleteData: req.query.deleteData, - }); + const soClient = (await context.core).savedObjects.getClient({ + includedHiddenTypes: [EntityDiscoveryApiKeyType.name], + }); - server.logger.debug('reading entity discovery API key from saved object'); - const apiKey = await readEntityDiscoveryAPIKey(server); - // api key could be deleted outside of the apis, it does not affect the - // disablement flow - if (apiKey) { - await deleteEntityDiscoveryAPIKey(soClient); - await server.security.authc.apiKeys.invalidateAsInternalUser({ - ids: [apiKey.id], - }); - } + await uninstallBuiltInEntityDefinitions({ + soClient, + esClient, + logger, + deleteData: params.query.deleteData, + }); - return res.ok({ body: { success: true } }); - } catch (err) { - logger.error(err); - return res.customError({ statusCode: 500, body: err }); + server.logger.debug('reading entity discovery API key from saved object'); + const apiKey = await readEntityDiscoveryAPIKey(server); + // api key could be deleted outside of the apis, it does not affect the + // disablement flow + if (apiKey) { + await deleteEntityDiscoveryAPIKey(soClient); + await server.security.authc.apiKeys.invalidateAsInternalUser({ + ids: [apiKey.id], + }); } + + return response.ok({ body: { success: true } }); + } catch (err) { + logger.error(err); + return response.customError({ statusCode: 500, body: err }); } - ); -} + }, +}); diff --git a/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/enable.ts b/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/enable.ts index 382e9a26ac6e5..a1d37de7c8df2 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/enable.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/enable.ts @@ -5,12 +5,9 @@ * 2.0. */ -import { RequestHandlerContext } from '@kbn/core/server'; -import { - CreateEntityDefinitionQuery, - createEntityDefinitionQuerySchema, -} from '@kbn/entities-schema'; -import { SetupRouteOptions } from '../types'; +import { createEntityDefinitionQuerySchema } from '@kbn/entities-schema'; +import { z } from '@kbn/zod'; +import { ERROR_API_KEY_SERVICE_DISABLED } from '../../../common/errors'; import { canEnableEntityDiscovery, checkIfAPIKeysAreEnabled, @@ -22,9 +19,9 @@ import { } from '../../lib/auth'; import { builtInDefinitions } from '../../lib/entities/built_in'; import { installBuiltInEntityDefinitions } from '../../lib/entities/install_entity_definition'; -import { ERROR_API_KEY_SERVICE_DISABLED } from '../../../common/errors'; -import { EntityDiscoveryApiKeyType } from '../../saved_objects'; import { startTransform } from '../../lib/entities/start_transform'; +import { EntityDiscoveryApiKeyType } from '../../saved_objects'; +import { createEntityManagerServerRoute } from '../create_entity_manager_server_route'; /** * @openapi @@ -42,14 +39,13 @@ import { startTransform } from '../../lib/entities/start_transform'; * type: boolean * default: false * responses: - * 403: - * description: The current user does not have the required permissions to enable entity discovery * 200: * description: OK - Verify result in response body * content: * application/json: * schema: * type: object + * required: success * properties: * success: * type: boolean @@ -60,90 +56,84 @@ import { startTransform } from '../../lib/entities/start_transform'; * message: * type: string * example: API key service is not enabled; try configuring `xpack.security.authc.api_key.enabled` in your elasticsearch config + * 403: + * description: The current user does not have the required permissions to enable entity discovery */ -export function enableEntityDiscoveryRoute({ - router, - server, - logger, -}: SetupRouteOptions) { - router.put( - { - path: '/internal/entities/managed/enablement', - validate: { - query: createEntityDefinitionQuerySchema, - }, - }, - async (context, req, res) => { - try { - const apiKeysEnabled = await checkIfAPIKeysAreEnabled(server); - if (!apiKeysEnabled) { - return res.ok({ - body: { - success: false, - reason: ERROR_API_KEY_SERVICE_DISABLED, - message: - 'API key service is not enabled; try configuring `xpack.security.authc.api_key.enabled` in your elasticsearch config', - }, - }); - } - - const esClient = (await context.core).elasticsearch.client.asCurrentUser; - const canEnable = await canEnableEntityDiscovery(esClient); - if (!canEnable) { - return res.forbidden({ - body: { - message: - 'Current Kibana user does not have the required permissions to enable entity discovery', - }, - }); - } +export const enableEntityDiscoveryRoute = createEntityManagerServerRoute({ + endpoint: 'PUT /internal/entities/managed/enablement', + params: z.object({ + query: createEntityDefinitionQuerySchema, + }), + handler: async ({ context, request, response, params, server, logger }) => { + try { + const apiKeysEnabled = await checkIfAPIKeysAreEnabled(server); + if (!apiKeysEnabled) { + return response.ok({ + body: { + success: false, + reason: ERROR_API_KEY_SERVICE_DISABLED, + message: + 'API key service is not enabled; try configuring `xpack.security.authc.api_key.enabled` in your elasticsearch config', + }, + }); + } - const soClient = (await context.core).savedObjects.getClient({ - includedHiddenTypes: [EntityDiscoveryApiKeyType.name], + const esClient = (await context.core).elasticsearch.client.asCurrentUser; + const canEnable = await canEnableEntityDiscovery(esClient); + if (!canEnable) { + return response.forbidden({ + body: { + message: + 'Current Kibana user does not have the required permissions to enable entity discovery', + }, }); - const existingApiKey = await readEntityDiscoveryAPIKey(server); + } - if (existingApiKey !== undefined) { - const isValid = await checkIfEntityDiscoveryAPIKeyIsValid(server, existingApiKey); + const soClient = (await context.core).savedObjects.getClient({ + includedHiddenTypes: [EntityDiscoveryApiKeyType.name], + }); + const existingApiKey = await readEntityDiscoveryAPIKey(server); - if (!isValid) { - await deleteEntityDiscoveryAPIKey(soClient); - await server.security.authc.apiKeys.invalidateAsInternalUser({ - ids: [existingApiKey.id], - }); - } - } + if (existingApiKey !== undefined) { + const isValid = await checkIfEntityDiscoveryAPIKeyIsValid(server, existingApiKey); - const apiKey = await generateEntityDiscoveryAPIKey(server, req); - if (apiKey === undefined) { - return res.customError({ - statusCode: 500, - body: new Error('could not generate entity discovery API key'), + if (!isValid) { + await deleteEntityDiscoveryAPIKey(soClient); + await server.security.authc.apiKeys.invalidateAsInternalUser({ + ids: [existingApiKey.id], }); } + } - await saveEntityDiscoveryAPIKey(soClient, apiKey); - - const installedDefinitions = await installBuiltInEntityDefinitions({ - esClient, - soClient, - logger, - definitions: builtInDefinitions, + const apiKey = await generateEntityDiscoveryAPIKey(server, request); + if (apiKey === undefined) { + return response.customError({ + statusCode: 500, + body: new Error('could not generate entity discovery API key'), }); + } - if (!req.query.installOnly) { - await Promise.all( - installedDefinitions.map((installedDefinition) => - startTransform(esClient, installedDefinition, logger) - ) - ); - } + await saveEntityDiscoveryAPIKey(soClient, apiKey); + + const installedDefinitions = await installBuiltInEntityDefinitions({ + esClient, + soClient, + logger, + definitions: builtInDefinitions, + }); - return res.ok({ body: { success: true } }); - } catch (err) { - logger.error(err); - return res.customError({ statusCode: 500, body: err }); + if (!params.query.installOnly) { + await Promise.all( + installedDefinitions.map((installedDefinition) => + startTransform(esClient, installedDefinition, logger) + ) + ); } + + return response.ok({ body: { success: true } }); + } catch (err) { + logger.error(err); + return response.customError({ statusCode: 500, body: err }); } - ); -} + }, +}); diff --git a/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/index.ts b/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/index.ts new file mode 100644 index 0000000000000..c7daae116af20 --- /dev/null +++ b/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { checkEntityDiscoveryEnabledRoute } from './check'; +import { enableEntityDiscoveryRoute } from './enable'; +import { disableEntityDiscoveryRoute } from './disable'; + +export const enablementRoutes = { + ...checkEntityDiscoveryEnabledRoute, + ...enableEntityDiscoveryRoute, + ...disableEntityDiscoveryRoute, +}; diff --git a/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/create.ts b/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/create.ts index 62a2b88cd99f8..114764444632f 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/create.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/create.ts @@ -5,18 +5,13 @@ * 2.0. */ -import { RequestHandlerContext } from '@kbn/core/server'; -import { - EntityDefinition, - entityDefinitionSchema, - createEntityDefinitionQuerySchema, - CreateEntityDefinitionQuery, -} from '@kbn/entities-schema'; -import { SetupRouteOptions } from '../types'; +import { createEntityDefinitionQuerySchema, entityDefinitionSchema } from '@kbn/entities-schema'; +import { z } from '@kbn/zod'; +import { EntityDefinitionIdInvalid } from '../../lib/entities/errors/entity_definition_id_invalid'; import { EntityIdConflict } from '../../lib/entities/errors/entity_id_conflict_error'; import { EntitySecurityException } from '../../lib/entities/errors/entity_security_exception'; import { InvalidTransformError } from '../../lib/entities/errors/invalid_transform_error'; -import { EntityDefinitionIdInvalid } from '../../lib/entities/errors/entity_definition_id_invalid'; +import { createEntityManagerServerRoute } from '../create_entity_manager_server_route'; /** * @openapi @@ -50,47 +45,39 @@ import { EntityDefinitionIdInvalid } from '../../lib/entities/errors/entity_defi * 409: * description: An entity definition with this ID already exists * 400: - * description: The entity definition cannot be installed; see the error for more details + * description: The entity definition cannot be installed; see the error for more details but commonly due to validation failures of the definition ID or metrics format */ -export function createEntityDefinitionRoute({ - router, - getScopedClient, - logger, -}: SetupRouteOptions) { - router.post( - { - path: '/internal/entities/definition', - validate: { - body: entityDefinitionSchema.strict(), - query: createEntityDefinitionQuerySchema, - }, - }, - async (context, request, res) => { - try { - const client = await getScopedClient({ request }); - const definition = await client.createEntityDefinition({ - definition: request.body, - installOnly: request.query.installOnly, - }); - - return res.ok({ body: definition }); - } catch (e) { - logger.error(e); +export const createEntityDefinitionRoute = createEntityManagerServerRoute({ + endpoint: 'POST /internal/entities/definition', + params: z.object({ + query: createEntityDefinitionQuerySchema, + body: entityDefinitionSchema, + }), + handler: async ({ request, response, params, logger, getScopedClient }) => { + try { + const client = await getScopedClient({ request }); + const definition = await client.createEntityDefinition({ + definition: params.body, + installOnly: params.query.installOnly, + }); - if (e instanceof EntityDefinitionIdInvalid) { - return res.badRequest({ body: e }); - } + return response.ok({ body: definition }); + } catch (e) { + logger.error(e); - if (e instanceof EntityIdConflict) { - return res.conflict({ body: e }); - } + if (e instanceof EntityDefinitionIdInvalid) { + return response.badRequest({ body: e }); + } - if (e instanceof EntitySecurityException || e instanceof InvalidTransformError) { - return res.customError({ body: e, statusCode: 400 }); - } + if (e instanceof EntityIdConflict) { + return response.conflict({ body: e }); + } - return res.customError({ body: e, statusCode: 500 }); + if (e instanceof EntitySecurityException || e instanceof InvalidTransformError) { + return response.customError({ body: e, statusCode: 400 }); } + + return response.customError({ body: e, statusCode: 500 }); } - ); -} + }, +}); diff --git a/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/delete.ts b/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/delete.ts index c2798aef9eb14..840f3746bc9bb 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/delete.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/delete.ts @@ -5,15 +5,15 @@ * 2.0. */ -import { RequestHandlerContext } from '@kbn/core/server'; import { deleteEntityDefinitionParamsSchema, deleteEntityDefinitionQuerySchema, } from '@kbn/entities-schema'; -import { SetupRouteOptions } from '../types'; +import { z } from '@kbn/zod'; +import { EntityDefinitionNotFound } from '../../lib/entities/errors/entity_not_found'; import { EntitySecurityException } from '../../lib/entities/errors/entity_security_exception'; import { InvalidTransformError } from '../../lib/entities/errors/invalid_transform_error'; -import { EntityDefinitionNotFound } from '../../lib/entities/errors/entity_not_found'; +import { createEntityManagerServerRoute } from '../create_entity_manager_server_route'; /** * @openapi @@ -49,39 +49,31 @@ import { EntityDefinitionNotFound } from '../../lib/entities/errors/entity_not_f * 404: * description: Entity definition with given ID not found */ -export function deleteEntityDefinitionRoute({ - router, - getScopedClient, - logger, -}: SetupRouteOptions) { - router.delete<{ id: string }, { deleteData?: boolean }, unknown>( - { - path: '/internal/entities/definition/{id}', - validate: { - params: deleteEntityDefinitionParamsSchema.strict(), - query: deleteEntityDefinitionQuerySchema.strict(), - }, - }, - async (context, request, res) => { - try { - const client = await getScopedClient({ request }); - await client.deleteEntityDefinition({ - id: request.params.id, - deleteData: request.query.deleteData, - }); +export const deleteEntityDefinitionRoute = createEntityManagerServerRoute({ + endpoint: 'DELETE /internal/entities/definition/{id}', + params: z.object({ + path: deleteEntityDefinitionParamsSchema, + query: deleteEntityDefinitionQuerySchema, + }), + handler: async ({ request, response, params, logger, getScopedClient }) => { + try { + const client = await getScopedClient({ request }); + await client.deleteEntityDefinition({ + id: params.path.id, + deleteData: params.query.deleteData, + }); - return res.ok({ body: { acknowledged: true } }); - } catch (e) { - logger.error(e); + return response.ok({ body: { acknowledged: true } }); + } catch (e) { + logger.error(e); - if (e instanceof EntityDefinitionNotFound) { - return res.notFound({ body: e }); - } - if (e instanceof EntitySecurityException || e instanceof InvalidTransformError) { - return res.customError({ body: e, statusCode: 400 }); - } - return res.customError({ body: e, statusCode: 500 }); + if (e instanceof EntityDefinitionNotFound) { + return response.notFound({ body: e }); + } + if (e instanceof EntitySecurityException || e instanceof InvalidTransformError) { + return response.customError({ body: e, statusCode: 400 }); } + return response.customError({ body: e, statusCode: 500 }); } - ); -} + }, +}); diff --git a/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/get.ts b/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/get.ts index 454679779c6a9..2c268aa315560 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/get.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/get.ts @@ -5,10 +5,9 @@ * 2.0. */ -import { z } from '@kbn/zod'; -import { RequestHandlerContext } from '@kbn/core/server'; import { getEntityDefinitionQuerySchema } from '@kbn/entities-schema'; -import { SetupRouteOptions } from '../types'; +import { z } from '@kbn/zod'; +import { createEntityManagerServerRoute } from '../create_entity_manager_server_route'; /** * @openapi @@ -49,32 +48,23 @@ import { SetupRouteOptions } from '../types'; * running: * type: boolean */ -export function getEntityDefinitionRoute({ - router, - getScopedClient, - logger, -}: SetupRouteOptions) { - router.get<{ id?: string }, { page?: number; perPage?: number }, unknown>( - { - path: '/internal/entities/definition/{id?}', - validate: { - query: getEntityDefinitionQuerySchema.strict(), - params: z.object({ id: z.optional(z.string()) }), - }, - }, - async (context, request, res) => { - try { - const client = await getScopedClient({ request }); - const result = await client.getEntityDefinitions({ - page: request.query.page, - perPage: request.query.perPage, - }); +export const getEntityDefinitionRoute = createEntityManagerServerRoute({ + endpoint: 'GET /internal/entities/definition', + params: z.object({ + query: getEntityDefinitionQuerySchema, + }), + handler: async ({ request, response, params, logger, getScopedClient }) => { + try { + const client = await getScopedClient({ request }); + const result = await client.getEntityDefinitions({ + page: params?.query?.page, + perPage: params?.query?.perPage, + }); - return res.ok({ body: result }); - } catch (e) { - logger.error(e); - return res.customError({ body: e, statusCode: 500 }); - } + return response.ok({ body: result }); + } catch (e) { + logger.error(e); + return response.customError({ body: e, statusCode: 500 }); } - ); -} + }, +}); diff --git a/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/index.ts b/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/index.ts new file mode 100644 index 0000000000000..539423c6a5e17 --- /dev/null +++ b/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/index.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createEntityDefinitionRoute } from './create'; +import { deleteEntityDefinitionRoute } from './delete'; +import { getEntityDefinitionRoute } from './get'; +import { resetEntityDefinitionRoute } from './reset'; +import { updateEntityDefinitionRoute } from './update'; + +export const entitiesRoutes = { + ...createEntityDefinitionRoute, + ...deleteEntityDefinitionRoute, + ...getEntityDefinitionRoute, + ...resetEntityDefinitionRoute, + ...updateEntityDefinitionRoute, +}; diff --git a/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/reset.ts b/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/reset.ts index b1fd385d22102..e6f4d18339a99 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/reset.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/reset.ts @@ -5,22 +5,8 @@ * 2.0. */ -import { RequestHandlerContext } from '@kbn/core/server'; import { resetEntityDefinitionParamsSchema } from '@kbn/entities-schema'; -import { SetupRouteOptions } from '../types'; -import { EntitySecurityException } from '../../lib/entities/errors/entity_security_exception'; -import { InvalidTransformError } from '../../lib/entities/errors/invalid_transform_error'; -import { readEntityDefinition } from '../../lib/entities/read_entity_definition'; -import { - stopAndDeleteHistoryBackfillTransform, - stopAndDeleteHistoryTransform, - stopAndDeleteLatestTransform, -} from '../../lib/entities/stop_and_delete_transform'; -import { - deleteHistoryIngestPipeline, - deleteLatestIngestPipeline, -} from '../../lib/entities/delete_ingest_pipeline'; -import { deleteIndices } from '../../lib/entities/delete_index'; +import { z } from '@kbn/zod'; import { createAndInstallHistoryIngestPipeline, createAndInstallLatestIngestPipeline, @@ -30,60 +16,67 @@ import { createAndInstallHistoryTransform, createAndInstallLatestTransform, } from '../../lib/entities/create_and_install_transform'; -import { startTransform } from '../../lib/entities/start_transform'; +import { deleteIndices } from '../../lib/entities/delete_index'; +import { + deleteHistoryIngestPipeline, + deleteLatestIngestPipeline, +} from '../../lib/entities/delete_ingest_pipeline'; import { EntityDefinitionNotFound } from '../../lib/entities/errors/entity_not_found'; +import { EntitySecurityException } from '../../lib/entities/errors/entity_security_exception'; +import { InvalidTransformError } from '../../lib/entities/errors/invalid_transform_error'; import { isBackfillEnabled } from '../../lib/entities/helpers/is_backfill_enabled'; +import { readEntityDefinition } from '../../lib/entities/read_entity_definition'; +import { startTransform } from '../../lib/entities/start_transform'; +import { + stopAndDeleteHistoryBackfillTransform, + stopAndDeleteHistoryTransform, + stopAndDeleteLatestTransform, +} from '../../lib/entities/stop_and_delete_transform'; +import { createEntityManagerServerRoute } from '../create_entity_manager_server_route'; -export function resetEntityDefinitionRoute({ - router, - logger, -}: SetupRouteOptions) { - router.post<{ id: string }, unknown, unknown>( - { - path: '/internal/entities/definition/{id}/_reset', - validate: { - params: resetEntityDefinitionParamsSchema.strict(), - }, - }, - async (context, req, res) => { - try { - const soClient = (await context.core).savedObjects.client; - const esClient = (await context.core).elasticsearch.client.asCurrentUser; +export const resetEntityDefinitionRoute = createEntityManagerServerRoute({ + endpoint: 'POST /internal/entities/definition/{id}/_reset', + params: z.object({ + path: resetEntityDefinitionParamsSchema, + }), + handler: async ({ context, response, params, logger }) => { + try { + const soClient = (await context.core).savedObjects.client; + const esClient = (await context.core).elasticsearch.client.asCurrentUser; - const definition = await readEntityDefinition(soClient, req.params.id, logger); + const definition = await readEntityDefinition(soClient, params.path.id, logger); - // Delete the transform and ingest pipeline - await stopAndDeleteHistoryTransform(esClient, definition, logger); - if (isBackfillEnabled(definition)) { - await stopAndDeleteHistoryBackfillTransform(esClient, definition, logger); - } - await stopAndDeleteLatestTransform(esClient, definition, logger); - await deleteHistoryIngestPipeline(esClient, definition, logger); - await deleteLatestIngestPipeline(esClient, definition, logger); - await deleteIndices(esClient, definition, logger); + // Delete the transform and ingest pipeline + await stopAndDeleteHistoryTransform(esClient, definition, logger); + if (isBackfillEnabled(definition)) { + await stopAndDeleteHistoryBackfillTransform(esClient, definition, logger); + } + await stopAndDeleteLatestTransform(esClient, definition, logger); + await deleteHistoryIngestPipeline(esClient, definition, logger); + await deleteLatestIngestPipeline(esClient, definition, logger); + await deleteIndices(esClient, definition, logger); - // Recreate everything - await createAndInstallHistoryIngestPipeline(esClient, definition, logger); - await createAndInstallLatestIngestPipeline(esClient, definition, logger); - await createAndInstallHistoryTransform(esClient, definition, logger); - if (isBackfillEnabled(definition)) { - await createAndInstallHistoryBackfillTransform(esClient, definition, logger); - } - await createAndInstallLatestTransform(esClient, definition, logger); - await startTransform(esClient, definition, logger); + // Recreate everything + await createAndInstallHistoryIngestPipeline(esClient, definition, logger); + await createAndInstallLatestIngestPipeline(esClient, definition, logger); + await createAndInstallHistoryTransform(esClient, definition, logger); + if (isBackfillEnabled(definition)) { + await createAndInstallHistoryBackfillTransform(esClient, definition, logger); + } + await createAndInstallLatestTransform(esClient, definition, logger); + await startTransform(esClient, definition, logger); - return res.ok({ body: { acknowledged: true } }); - } catch (e) { - logger.error(e); + return response.ok({ body: { acknowledged: true } }); + } catch (e) { + logger.error(e); - if (e instanceof EntityDefinitionNotFound) { - return res.notFound({ body: e }); - } - if (e instanceof EntitySecurityException || e instanceof InvalidTransformError) { - return res.customError({ body: e, statusCode: 400 }); - } - return res.customError({ body: e, statusCode: 500 }); + if (e instanceof EntityDefinitionNotFound) { + return response.notFound({ body: e }); + } + if (e instanceof EntitySecurityException || e instanceof InvalidTransformError) { + return response.customError({ body: e, statusCode: 400 }); } + return response.customError({ body: e, statusCode: 500 }); } - ); -} + }, +}); diff --git a/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/update.ts b/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/update.ts index 0668287d6d765..99dee233a0e40 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/update.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/update.ts @@ -5,28 +5,25 @@ * 2.0. */ -import { z } from '@kbn/zod'; -import { RequestHandlerContext } from '@kbn/core/server'; import { createEntityDefinitionQuerySchema, - CreateEntityDefinitionQuery, entityDefinitionUpdateSchema, - EntityDefinitionUpdate, } from '@kbn/entities-schema'; -import { SetupRouteOptions } from '../types'; +import { z } from '@kbn/zod'; import { EntitySecurityException } from '../../lib/entities/errors/entity_security_exception'; import { InvalidTransformError } from '../../lib/entities/errors/invalid_transform_error'; -import { startTransform } from '../../lib/entities/start_transform'; +import { findEntityDefinitionById } from '../../lib/entities/find_entity_definition'; import { installationInProgress, reinstallEntityDefinition, } from '../../lib/entities/install_entity_definition'; -import { findEntityDefinitionById } from '../../lib/entities/find_entity_definition'; +import { startTransform } from '../../lib/entities/start_transform'; +import { createEntityManagerServerRoute } from '../create_entity_manager_server_route'; /** * @openapi * /internal/entities/definition: - * put: + * patch: * description: Update an entity definition. * tags: * - definitions @@ -61,71 +58,63 @@ import { findEntityDefinitionById } from '../../lib/entities/find_entity_definit * 409: * description: The entity definition is being updated by another request */ -export function updateEntityDefinitionRoute({ - router, - server, -}: SetupRouteOptions) { - router.patch<{ id: string }, CreateEntityDefinitionQuery, EntityDefinitionUpdate>( - { - path: '/internal/entities/definition/{id}', - validate: { - body: entityDefinitionUpdateSchema.strict(), - query: createEntityDefinitionQuerySchema, - params: z.object({ id: z.string() }), - }, - }, - async (context, req, res) => { - const { logger } = server; - const core = await context.core; - const soClient = core.savedObjects.client; - const esClient = core.elasticsearch.client.asCurrentUser; - - try { - const installedDefinition = await findEntityDefinitionById({ - soClient, - esClient, - id: req.params.id, - }); +export const updateEntityDefinitionRoute = createEntityManagerServerRoute({ + endpoint: 'PATCH /internal/entities/definition/{id}', + params: z.object({ + path: z.object({ id: z.string() }), + query: createEntityDefinitionQuerySchema, + body: entityDefinitionUpdateSchema, + }), + handler: async ({ context, response, params, logger }) => { + const core = await context.core; + const soClient = core.savedObjects.client; + const esClient = core.elasticsearch.client.asCurrentUser; - if (!installedDefinition) { - return res.notFound({ - body: { message: `Entity definition [${req.params.id}] not found` }, - }); - } + try { + const installedDefinition = await findEntityDefinitionById({ + soClient, + esClient, + id: params.path.id, + }); - if (installedDefinition.managed) { - return res.forbidden({ - body: { message: `Managed definition cannot be modified` }, - }); - } + if (!installedDefinition) { + return response.notFound({ + body: { message: `Entity definition [${params.path.id}] not found` }, + }); + } - if (installationInProgress(installedDefinition)) { - return res.conflict({ - body: { message: `Entity definition [${req.params.id}] has changes in progress` }, - }); - } + if (installedDefinition.managed) { + return response.forbidden({ + body: { message: `Managed definition cannot be modified` }, + }); + } - const updatedDefinition = await reinstallEntityDefinition({ - soClient, - esClient, - logger, - definition: installedDefinition, - definitionUpdate: req.body, + if (installationInProgress(installedDefinition)) { + return response.conflict({ + body: { message: `Entity definition [${params.path.id}] has changes in progress` }, }); + } + + const updatedDefinition = await reinstallEntityDefinition({ + soClient, + esClient, + logger, + definition: installedDefinition, + definitionUpdate: params.body, + }); - if (!req.query.installOnly) { - await startTransform(esClient, updatedDefinition, logger); - } + if (!params.query.installOnly) { + await startTransform(esClient, updatedDefinition, logger); + } - return res.ok({ body: updatedDefinition }); - } catch (e) { - logger.error(e); + return response.ok({ body: updatedDefinition }); + } catch (e) { + logger.error(e); - if (e instanceof EntitySecurityException || e instanceof InvalidTransformError) { - return res.customError({ body: e, statusCode: 400 }); - } - return res.customError({ body: e, statusCode: 500 }); + if (e instanceof EntitySecurityException || e instanceof InvalidTransformError) { + return response.customError({ body: e, statusCode: 400 }); } + return response.customError({ body: e, statusCode: 500 }); } - ); -} + }, +}); diff --git a/x-pack/plugins/observability_solution/entity_manager/server/routes/index.ts b/x-pack/plugins/observability_solution/entity_manager/server/routes/index.ts index 2fb9734187119..e3f2d3a75bbef 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/routes/index.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/routes/index.ts @@ -5,24 +5,12 @@ * 2.0. */ -import { RequestHandlerContext } from '@kbn/core/server'; -import { SetupRouteOptions } from './types'; -import { createEntityDefinitionRoute } from './entities/create'; -import { deleteEntityDefinitionRoute } from './entities/delete'; -import { resetEntityDefinitionRoute } from './entities/reset'; -import { getEntityDefinitionRoute } from './entities/get'; -import { updateEntityDefinitionRoute } from './entities/update'; -import { checkEntityDiscoveryEnabledRoute } from './enablement/check'; -import { enableEntityDiscoveryRoute } from './enablement/enable'; -import { disableEntityDiscoveryRoute } from './enablement/disable'; +import { enablementRoutes } from './enablement'; +import { entitiesRoutes } from './entities'; -export function setupRoutes(dependencies: SetupRouteOptions) { - createEntityDefinitionRoute(dependencies); - deleteEntityDefinitionRoute(dependencies); - resetEntityDefinitionRoute(dependencies); - getEntityDefinitionRoute(dependencies); - checkEntityDiscoveryEnabledRoute(dependencies); - enableEntityDiscoveryRoute(dependencies); - disableEntityDiscoveryRoute(dependencies); - updateEntityDefinitionRoute(dependencies); -} +export const entityManagerRouteRepository = { + ...enablementRoutes, + ...entitiesRoutes, +}; + +export type EntityManagerRouteRepository = typeof entityManagerRouteRepository; diff --git a/x-pack/plugins/observability_solution/entity_manager/server/routes/types.ts b/x-pack/plugins/observability_solution/entity_manager/server/routes/types.ts index d4d8cfba815ae..ad5331340b22b 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/routes/types.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/routes/types.ts @@ -5,14 +5,15 @@ * 2.0. */ -import { IRouter, KibanaRequest, RequestHandlerContextBase } from '@kbn/core-http-server'; -import { Logger } from '@kbn/core/server'; -import { EntityManagerServerSetup } from '../types'; +import { KibanaRequest } from '@kbn/core-http-server'; +import { DefaultRouteHandlerResources } from '@kbn/server-route-repository'; import { EntityClient } from '../lib/entity_client'; +import { EntityManagerServerSetup } from '../types'; -export interface SetupRouteOptions { - router: IRouter; +export interface EntityManagerRouteDependencies { server: EntityManagerServerSetup; - logger: Logger; getScopedClient: ({ request }: { request: KibanaRequest }) => Promise; } + +export type EntityManagerRouteHandlerResources = EntityManagerRouteDependencies & + DefaultRouteHandlerResources; diff --git a/x-pack/plugins/observability_solution/entity_manager/tsconfig.json b/x-pack/plugins/observability_solution/entity_manager/tsconfig.json index cba8dbcd50fee..537e31e9bda93 100644 --- a/x-pack/plugins/observability_solution/entity_manager/tsconfig.json +++ b/x-pack/plugins/observability_solution/entity_manager/tsconfig.json @@ -28,6 +28,9 @@ "@kbn/encrypted-saved-objects-plugin", "@kbn/logging-mocks", "@kbn/licensing-plugin", + "@kbn/server-route-repository-client", + "@kbn/server-route-repository", "@kbn/zod", + "@kbn/zod-helpers", ] } From 426eb898f071d825f1a230bd64880b2c9de825c1 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Fri, 6 Sep 2024 11:13:25 +0200 Subject: [PATCH 72/99] [Search] [Playground] Fix connectors broken page (#191852) - Fix load connector page on edit route - Fix showing documentation and create connectors button on edit connector page - Add unit tests - Add ftr test --- .../actions_connectors_home.test.tsx | 33 +++++++++++++ .../components/actions_connectors_home.tsx | 32 +++++++----- .../actions_connectors_list.test.tsx | 49 ++++++++++++++----- .../playground_overview.ess.ts | 4 ++ .../page_objects/search_playground_page.ts | 9 ++++ .../search_playground/playground_overview.ts | 4 ++ 6 files changed, 105 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_home.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_home.test.tsx index 7c87676ae0bd0..e95e49843fd78 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_home.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_home.test.tsx @@ -143,6 +143,39 @@ describe('ActionsConnectorsHome', () => { expect(documentationButton).toBeEnabled(); }); + it('show "Create connector" and "Documentation" buttons when on Connectors Edit tab', async () => { + const props: RouteComponentProps = { + history: createMemoryHistory({ + initialEntries: ['/connectors/1'], + }), + location: createLocation('/connectors/1'), + match: { + isExact: true, + path: '/connectors/1', + url: '', + params: { + section: 'connectors', + }, + }, + }; + + render( + + + + + + + + ); + + const createConnectorButton = await screen.findByRole('button', { name: 'Create connector' }); + expect(createConnectorButton).toBeEnabled(); + + const documentationButton = await screen.findByRole('link', { name: 'Documentation' }); + expect(documentationButton).toBeEnabled(); + }); + it('hide "Create connector" button when on Logs tab', async () => { const props: RouteComponentProps = { history: createMemoryHistory({ diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_home.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_home.tsx index 3611797da36af..e2671ae7246b8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_home.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_home.tsx @@ -8,7 +8,7 @@ import React, { lazy, useCallback, useEffect, useState } from 'react'; import { RouteComponentProps } from 'react-router-dom'; import { Routes, Route } from '@kbn/shared-ux-router'; -import { useLocation } from 'react-router-dom'; +import { useLocation, matchPath } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { EuiPageTemplate, EuiSpacer, EuiPageHeader, EuiButton, EuiButtonEmpty } from '@elastic/eui'; @@ -54,9 +54,12 @@ export const ActionsConnectorsHome: React.FunctionComponent([]); const [isLoadingActions, setIsLoadingActions] = useState(true); - const editItem = (actionConnector: ActionConnector, tab: EditConnectorTabs, isFix?: boolean) => { - setEditConnectorProps({ initialConnector: actionConnector, tab, isFix: isFix ?? false }); - }; + const editItem = useCallback( + (actionConnector: ActionConnector, tab: EditConnectorTabs, isFix?: boolean) => { + setEditConnectorProps({ initialConnector: actionConnector, tab, isFix: isFix ?? false }); + }, + [setEditConnectorProps] + ); const loadActions = useCallback(async () => { setIsLoadingActions(true); @@ -176,16 +179,19 @@ export const ActionsConnectorsHome: React.FunctionComponent ({ loadAllActions: jest.fn(), loadActionTypes: jest.fn(), })); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: jest.fn().mockReturnValue({}), + useLocation: jest.fn().mockReturnValue({ search: '' }), + useHistory: jest.fn().mockReturnValue({ push: jest.fn(), createHref: jest.fn() }), +})); + const useKibanaMock = useKibana as jest.Mocked; const actionTypeRegistry = actionTypeRegistryMock.create(); const mocks = coreMock.createSetup(); const { loadActionTypes } = jest.requireMock('../../../lib/action_connector_api'); -const mockGetParams = jest.fn().mockReturnValue({}); -const mockGetLocation = jest.fn().mockReturnValue({ search: '' }); -const mockGetHistory = jest.fn().mockReturnValue({ push: jest.fn(), createHref: jest.fn() }); - -jest.mock('react-router-dom', () => ({ - useParams: () => mockGetParams(), - useLocation: () => mockGetLocation(), - useHistory: () => mockGetHistory(), -})); describe('actions_connectors_list', () => { describe('component empty', () => { @@ -173,6 +172,15 @@ describe('actions_connectors_list', () => { config: {}, }, ] as ActionConnector[]; + let mockedEditItem: jest.Mock; + + afterEach(() => { + mockedEditItem.mockReset(); + }); + + afterAll(() => { + jest.clearAllMocks(); + }); async function setup(actionConnectors = mockedActions) { loadActionTypes.mockResolvedValueOnce([ @@ -237,13 +245,13 @@ describe('actions_connectors_list', () => { }, }; - const editItem = jest.fn(); + mockedEditItem = jest.fn(); wrapper = mountWithIntl( {}} loadActions={async () => {}} - editItem={editItem} + editItem={mockedEditItem} isLoadingActions={false} actions={actionConnectors} setActions={() => {}} @@ -379,6 +387,21 @@ describe('actions_connectors_list', () => { .includes('This connector is used in a rule') ); }); + + it('call editItem when connectorId presented in url', async () => { + const selectedConnector = mockedActions[3]; + const mockedCreateHref = jest.fn(({ pathname }) => pathname); + const replaceStateSpy = jest.spyOn(window.history, 'replaceState'); + (useParams as jest.Mock).mockReturnValue({ connectorId: selectedConnector.id }); + (useHistory as jest.Mock).mockReturnValue({ createHref: mockedCreateHref }); + + await setup(); + + expect(mockedEditItem).toBeCalledWith(selectedConnector, EditConnectorTabs.Configuration); + expect(mockedCreateHref).toHaveBeenCalledWith({ pathname: '/connectors' }); + expect(replaceStateSpy).toHaveBeenCalledWith(null, '', '/connectors'); + replaceStateSpy.mockRestore(); + }); }); describe('check EditConnectorFlyout will open on edit connector', () => { diff --git a/x-pack/test/functional/apps/search_playground/playground_overview.ess.ts b/x-pack/test/functional/apps/search_playground/playground_overview.ess.ts index 31f8b32eec594..e64fafd4b010f 100644 --- a/x-pack/test/functional/apps/search_playground/playground_overview.ess.ts +++ b/x-pack/test/functional/apps/search_playground/playground_overview.ess.ts @@ -171,6 +171,10 @@ export default function (ftrContext: FtrProviderContext) { it('save selected fields between modes', async () => { await pageObjects.searchPlayground.PlaygroundChatPage.expectSaveFieldsBetweenModes(); }); + + it('click on manage connector button', async () => { + await pageObjects.searchPlayground.PlaygroundChatPage.clickManageButton(); + }); }); after(async () => { diff --git a/x-pack/test/functional/page_objects/search_playground_page.ts b/x-pack/test/functional/page_objects/search_playground_page.ts index d03457298a7c7..9b44addce9e25 100644 --- a/x-pack/test/functional/page_objects/search_playground_page.ts +++ b/x-pack/test/functional/page_objects/search_playground_page.ts @@ -231,6 +231,15 @@ export function SearchPlaygroundPageProvider({ getService }: FtrProviderContext) await testSubjects.click('queryMode'); await testSubjects.existOrFail('field-baz-false'); }, + + async clickManageButton() { + await testSubjects.click('manageConnectorsLink'); + await testSubjects.existOrFail('manageConnectorsLink'); + await browser.switchTab(1); + await testSubjects.existOrFail('edit-connector-flyout'); + await browser.closeCurrentWindow(); + await browser.switchTab(0); + }, }, }; } diff --git a/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts b/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts index 9545707c51540..44d96d565fec2 100644 --- a/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts +++ b/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts @@ -207,6 +207,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await pageObjects.searchPlayground.session.expectInSession('prompt', "You're a doctor"); await pageObjects.searchPlayground.session.expectInSession('question', undefined); }); + + it('click on manage connector button', async () => { + await pageObjects.searchPlayground.PlaygroundChatPage.clickManageButton(); + }); }); after(async () => { From bec511731d545beedb0a3493e1c17416a66fe70b Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Fri, 6 Sep 2024 11:28:23 +0200 Subject: [PATCH 73/99] [react@18] fix `field.helpText` type issue (#192083) ## Summary Part of https://github.com/elastic/kibana/issues/138222 This is one of the issues that `@types/react@18` upgrade highlights and that needs to be addressed with or before the upgrade. `field.helpText` is `ReactNode`, a function is not a valid `ReactNode`, but `@types/react@17` allowed a function. That is why `typeof field.helpText === 'function' ? field.helpText() : field.helpText` doesn't fail with `@17`, but fails with `@18` as `field.helpText is not callable, as never is not callable`. You can check the types with @types/react@18 yourself here https://github.com/elastic/kibana/pull/191738 It looks like the lazy `helpText` isn't needed apart from a hack for index management where documentation service is used as part of helpText that could be not available yet. To keep it supported, I specifically, allowed a function that returns a ReactNode for `helpText` on `FieldConfig`, but to make consumption clean and to now break other places `useField` will call it and pass just a `ReactNode` down --- .../public/components/form_fields/title_field.tsx | 2 +- .../static/forms/components/fields/button_group_field.tsx | 2 +- .../static/forms/components/fields/card_radio_group_field.tsx | 2 +- .../static/forms/components/fields/checkbox_field.tsx | 2 +- .../static/forms/components/fields/combobox_field.tsx | 2 +- .../static/forms/components/fields/date_picker_field.tsx | 2 +- .../static/forms/components/fields/file_picker_field.tsx | 2 +- .../forms/components/fields/multi_button_group_field.tsx | 2 +- .../static/forms/components/fields/multi_select_field.tsx | 2 +- .../static/forms/components/fields/numeric_field.tsx | 2 +- .../static/forms/components/fields/password_field.tsx | 2 +- .../static/forms/components/fields/radio_group_field.tsx | 2 +- .../static/forms/components/fields/range_field.tsx | 2 +- .../static/forms/components/fields/select_field.tsx | 2 +- .../static/forms/components/fields/super_select_field.tsx | 2 +- .../static/forms/components/fields/text_area_field.tsx | 2 +- .../static/forms/components/fields/text_field.tsx | 2 +- .../static/forms/components/fields/toggle_field.tsx | 2 +- .../es_ui_shared/static/forms/docs/examples/style_fields.mdx | 2 +- .../es_ui_shared/static/forms/docs/examples/validation.mdx | 2 +- .../static/forms/hook_form_lib/hooks/use_field.ts | 2 +- src/plugins/es_ui_shared/static/forms/hook_form_lib/types.ts | 2 +- .../enrich_policy_create/steps/fields/indices_selector.tsx | 2 +- .../application/components/mustache_text_field_wrapper.tsx | 2 +- .../components/text_field_with_message_variables.tsx | 4 ++-- 25 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/plugins/data_view_editor/public/components/form_fields/title_field.tsx b/src/plugins/data_view_editor/public/components/form_fields/title_field.tsx index 5428f5455aeea..9ebfae668a3da 100644 --- a/src/plugins/data_view_editor/public/components/form_fields/title_field.tsx +++ b/src/plugins/data_view_editor/public/components/form_fields/title_field.tsx @@ -170,7 +170,7 @@ export const TitleField = ({ return ( { return ( diff --git a/src/plugins/es_ui_shared/static/forms/docs/examples/validation.mdx b/src/plugins/es_ui_shared/static/forms/docs/examples/validation.mdx index c45cae8602f19..3e09bd173fd73 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/examples/validation.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/examples/validation.mdx @@ -56,7 +56,7 @@ export const MyComponent = () => { return ( diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.ts index 324a2ea1255a8..c73ce9aab369e 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.ts @@ -549,7 +549,7 @@ export const useField = ( type, label, labelAppend, - helpText, + helpText: typeof helpText === 'function' ? helpText() : helpText, value, errors, isPristine, diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/types.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/types.ts index a7cc46717b179..259ad8d7893ff 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/types.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/types.ts @@ -211,7 +211,7 @@ export interface FieldHook { export interface FieldConfig { readonly label?: string; readonly labelAppend?: string | ReactNode; - readonly helpText?: string | ReactNode; + readonly helpText?: string | ReactNode | (() => ReactNode); readonly type?: string; readonly defaultValue?: T; readonly validations?: Array>; diff --git a/x-pack/plugins/index_management/public/application/sections/enrich_policy_create/steps/fields/indices_selector.tsx b/x-pack/plugins/index_management/public/application/sections/enrich_policy_create/steps/fields/indices_selector.tsx index f246527b9dfdc..9181449f2dbac 100644 --- a/x-pack/plugins/index_management/public/application/sections/enrich_policy_create/steps/fields/indices_selector.tsx +++ b/x-pack/plugins/index_management/public/application/sections/enrich_policy_create/steps/fields/indices_selector.tsx @@ -90,7 +90,7 @@ export const IndicesSelector = ({ field, euiFieldProps, ...rest }: Props) => { Date: Fri, 6 Sep 2024 11:54:08 +0200 Subject: [PATCH 74/99] [ResponseOps][Connectors] Highlight step as optional in connector creation form (#191918) ## Summary I have added the `(optional)` text to step 4 of the `Webhook - Case management` creation form. ### Before ![before](https://github.com/user-attachments/assets/f0e7e76b-335f-4ac7-bcb0-a179ec222c0b) ### After Screenshot 2024-09-02 at 14 32 39 Co-authored-by: Elastic Machine --- .../public/connector_types/cases_webhook/translations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/translations.ts index 5986126d17adc..0b007e07cfd91 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/translations.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/translations.ts @@ -340,7 +340,7 @@ export const STEP_4A_DESCRIPTION = i18n.translate( ); export const STEP_4B = i18n.translate('xpack.stackConnectors.components.casesWebhook.step4b', { - defaultMessage: 'Add comment in case', + defaultMessage: 'Add comment in case (optional)', }); export const STEP_4B_DESCRIPTION = i18n.translate( From ab1646f4e40f3cc472fbd125c298b5f180e936e2 Mon Sep 17 00:00:00 2001 From: Elena Shostak <165678770+elena-shostak@users.noreply.github.com> Date: Fri, 6 Sep 2024 12:26:40 +0200 Subject: [PATCH 75/99] [Spaces] Excluded roles with reserved only privileges (#192041) ## Summary Excluded roles with reserved only privileges `/internal/security/roles/{spaceId}` route. `_reserved` privileges are legacy, and they do not grant access to spaces directly, but rather rely on other roles to grant that access in order to function. ### 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 __Fixes: https://github.com/elastic/kibana/issues/191996__ --------- Co-authored-by: Elastic Machine --- .../roles/get_all_by_space.test.ts | 76 +++++++++++++++++++ .../authorization/roles/get_all_by_space.ts | 44 +++++++---- 2 files changed, 107 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get_all_by_space.test.ts b/x-pack/plugins/security/server/routes/authorization/roles/get_all_by_space.test.ts index 4fd330cae2af8..f918fa983c701 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get_all_by_space.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get_all_by_space.test.ts @@ -320,5 +320,81 @@ describe('GET all roles by space id', () => { ], }, }); + + getRolesTest(`filters roles with reserved only privileges`, { + apiResponse: () => ({ + first_role: { + description: 'first role description', + cluster: [], + indices: [], + applications: [], + run_as: [], + metadata: { + _reserved: true, + }, + transient_metadata: { + enabled: true, + }, + }, + second_role: { + cluster: [], + indices: [], + applications: [ + { + application, + privileges: ['space_all', 'space_read'], + resources: ['space:marketing', 'space:sales'], + }, + ], + run_as: [], + metadata: { + _reserved: true, + }, + transient_metadata: { + enabled: true, + }, + }, + third_role: { + cluster: [], + indices: [], + applications: [], + run_as: [], + transient_metadata: { + enabled: true, + }, + }, + }), + spaceId: 'marketing', + asserts: { + statusCode: 200, + result: [ + { + _transform_error: [], + _unrecognized_applications: [], + elasticsearch: { + cluster: [], + indices: [], + remote_cluster: undefined, + remote_indices: undefined, + run_as: [], + }, + kibana: [ + { + base: ['all', 'read'], + feature: {}, + spaces: ['marketing', 'sales'], + }, + ], + metadata: { + _reserved: true, + }, + name: 'second_role', + transient_metadata: { + enabled: true, + }, + }, + ], + }, + }); }); }); diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get_all_by_space.ts b/x-pack/plugins/security/server/routes/authorization/roles/get_all_by_space.ts index 3ac74cade0202..9cfdf3ba301ac 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get_all_by_space.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get_all_by_space.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import type { RouteDefinitionParams } from '../..'; +import type { Role } from '../../../../common'; import { ALL_SPACES_ID } from '../../../../common/constants'; import { compareRolesByName, transformElasticsearchRoleToRole } from '../../../authorization'; import { wrapIntoCustomErrorResponse } from '../../../errors'; @@ -43,25 +44,42 @@ export function defineGetAllRolesBySpaceRoutes({ // Transform elasticsearch roles into Kibana roles and return in a list sorted by the role name. return response.ok({ body: Object.entries(elasticsearchRoles) - .map(([roleName, elasticsearchRole]) => - transformElasticsearchRoleToRole( + .reduce((acc, [roleName, elasticsearchRole]) => { + if (hideReservedRoles && elasticsearchRole.metadata?._reserved) { + return acc; + } + + const role = transformElasticsearchRoleToRole( features, // @ts-expect-error @elastic/elasticsearch SecurityIndicesPrivileges.names expected to be string[] elasticsearchRole, roleName, authz.applicationName, logger - ) - ) - .filter( - (role) => - !(hideReservedRoles && role.metadata?._reserved) && - role.kibana.some( - (privilege) => - privilege.spaces.includes(request.params.spaceId) || - privilege.spaces.includes(ALL_SPACES_ID) - ) - ) + ); + + const includeRoleForSpace = role.kibana.some((privilege) => { + const privilegeInSpace = + privilege.spaces.includes(request.params.spaceId) || + privilege.spaces.includes(ALL_SPACES_ID); + + if (privilegeInSpace && privilege.base.length) { + return true; + } + + const hasFeaturePrivilege = Object.values(privilege.feature).some( + (featureList) => featureList.length + ); + + return privilegeInSpace && hasFeaturePrivilege; + }); + + if (includeRoleForSpace) { + acc.push(role); + } + + return acc; + }, []) .sort(compareRolesByName), }); } catch (error) { From ad7d935de0101732af7436519769b0be206ed8ad Mon Sep 17 00:00:00 2001 From: Yngrid Coello Date: Fri, 6 Sep 2024 12:49:27 +0200 Subject: [PATCH 76/99] [Dataset quality] removing empty prompt (#192089) The empty prompt as of now is just informative After introducing other dataStream types within the page, the empty prompt became a hindrance in the UX preventing users to properly select a dataStream type when they have no data related to that type in the environment. This PR is about removing the empty prompt in favour of an empty state. We want to keep the prompt only in case we have a place where to redirect users to add relevant data ([ref](https://github.com/elastic/kibana/issues/191821)). ### Before https://github.com/user-attachments/assets/f294e37e-3a4e-430a-acd4-73a7acd21178 ### After https://github.com/user-attachments/assets/c24cd62b-0fc0-4a94-8f45-d8f7ec4da6f1 --- .../empty_state/empty_state.tsx | 29 +------------------ .../public/hooks/use_empty_state.ts | 12 +------- .../translations/translations/fr-FR.json | 2 -- .../translations/translations/ja-JP.json | 2 -- .../translations/translations/zh-CN.json | 2 -- .../page_objects/dataset_quality.ts | 2 +- 6 files changed, 3 insertions(+), 46 deletions(-) diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/empty_state/empty_state.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/empty_state/empty_state.tsx index 9ff2982098498..1fabd455ec9c2 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/empty_state/empty_state.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/empty_state/empty_state.tsx @@ -16,7 +16,7 @@ import { useEmptyState } from '../../../hooks/use_empty_state'; // Allow for lazy loading // eslint-disable-next-line import/no-default-export export default function EmptyStateWrapper({ children }: { children: React.ReactNode }) { - const { canReadDataset, isDatasetEmpty } = useEmptyState(); + const { canReadDataset } = useEmptyState(); if (!canReadDataset) { return ( @@ -46,32 +46,5 @@ export default function EmptyStateWrapper({ children }: { children: React.ReactN ); } - if (isDatasetEmpty) { - return ( - - {i18n.translate('xpack.datasetQuality.emptyState.noData.title', { - defaultMessage: 'No datasets found', - })} - - } - body={ -

- {DEFAULT_LOGS_DATA_VIEW}, - }} - /> -

- } - /> - ); - } - return <>{children}; } diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_empty_state.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_empty_state.ts index f60a7914275be..89ef4b884095d 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_empty_state.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_empty_state.ts @@ -14,15 +14,5 @@ export function useEmptyState() { service, (state) => state.context.datasetUserPrivileges.canRead ); - - const isDatasetEmpty = useSelector( - service, - (state) => - !state.matches('stats.datasets.fetching') && - !state.matches('integrations.fetching') && - !state.matches('stats.degradedDocs.fetching') && - (state.context.datasets?.length ?? 0) === 0 - ); - - return { canReadDataset, isDatasetEmpty }; + return { canReadDataset }; } diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 6b67be558d471..2fb444ad60020 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -14610,8 +14610,6 @@ "xpack.datasetQuality.degradedDocsColumnName": "Documents dégradés (%)", "xpack.datasetQuality.degradedDocsColumnTooltip": "Le pourcentage de documents avec la propriété {ignoredProperty} dans votre ensemble de données.", "xpack.datasetQuality.degradedDocsQualityDescription": "{quality} -{comparator} {minimimPercentage}%", - "xpack.datasetQuality.emptyState.noData.message": "Aucun log d'ensemble de données n'a été trouvé. Pour commencer, assurez-vous d'avoir des logs de flux de données disponibles correspondant à {datasetPattern}.", - "xpack.datasetQuality.emptyState.noData.title": "Aucun ensemble de données trouvé", "xpack.datasetQuality.emptyState.noPrivileges.message": "Vous ne disposez pas des autorisations requises pour voir les données de logs. Assurez-vous d'avoir les autorisations requises pour voir {datasetPattern}.", "xpack.datasetQuality.emptyState.noPrivileges.title": "Impossible de charger les ensembles de données", "xpack.datasetQuality.fetchDatasetStatsFailed": "Nous n'avons pas pu obtenir vos ensembles de données.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index d393af049ecd8..b9c6d9ab1758c 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -14599,8 +14599,6 @@ "xpack.datasetQuality.degradedDocsColumnName": "劣化したドキュメント(%)", "xpack.datasetQuality.degradedDocsColumnTooltip": "データセットにおける{ignoredProperty}プロパティのドキュメントの割合。", "xpack.datasetQuality.degradedDocsQualityDescription": "{quality} -{comparator} {minimimPercentage}%", - "xpack.datasetQuality.emptyState.noData.message": "ログデータセットが見つかりません。開始するには、{datasetPattern}と一致するログデータストリームがあることを確認してください。", - "xpack.datasetQuality.emptyState.noData.title": "データセットが見つかりません", "xpack.datasetQuality.emptyState.noPrivileges.message": "ログデータを表示するために必要な権限がありません。{datasetPattern}を表示するための十分な権限があることを確認してください。", "xpack.datasetQuality.emptyState.noPrivileges.title": "データセットを読み込めませんでした", "xpack.datasetQuality.fetchDatasetStatsFailed": "データセットを取得できませんでした。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index b6edb38251ae1..a573ea4868a10 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -14622,8 +14622,6 @@ "xpack.datasetQuality.degradedDocsColumnName": "已降级文档 (%)", "xpack.datasetQuality.degradedDocsColumnTooltip": "您的数据集中包含 {ignoredProperty} 属性的文档的百分比。", "xpack.datasetQuality.degradedDocsQualityDescription": "{quality} -{comparator} {minimimPercentage}%", - "xpack.datasetQuality.emptyState.noData.message": "找不到日志数据集。要开始,请确保具有与 {datasetPattern} 匹配的可用日志数据流。", - "xpack.datasetQuality.emptyState.noData.title": "找不到数据集", "xpack.datasetQuality.emptyState.noPrivileges.message": "您没有查看日志数据所需的权限。请确保您具有足够的权限,可以查看 {datasetPattern}。", "xpack.datasetQuality.emptyState.noPrivileges.title": "无法加载数据集", "xpack.datasetQuality.fetchDatasetStatsFailed": "无法获取数据集。", diff --git a/x-pack/test/functional/page_objects/dataset_quality.ts b/x-pack/test/functional/page_objects/dataset_quality.ts index 29dd452c7592c..437aa6e2640d5 100644 --- a/x-pack/test/functional/page_objects/dataset_quality.ts +++ b/x-pack/test/functional/page_objects/dataset_quality.ts @@ -120,7 +120,7 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv datasetQualityDetailsIntegrationRowVersion: 'datasetQualityDetailsFieldsList-version', datasetQualityDetailsLinkToDiscover: 'datasetQualityDetailsLinkToDiscover', datasetQualityInsufficientPrivileges: 'datasetQualityInsufficientPrivileges', - datasetQualityNoDataEmptyState: 'datasetQualityNoDataEmptyState', + datasetQualityNoDataEmptyState: 'datasetQualityTableNoData', datasetQualityNoPrivilegesEmptyState: 'datasetQualityNoPrivilegesEmptyState', superDatePickerToggleQuickMenuButton: 'superDatePickerToggleQuickMenuButton', From d8445ccab6cff2b2d4f238ecf6f4af245af72ba0 Mon Sep 17 00:00:00 2001 From: Yngrid Coello Date: Fri, 6 Sep 2024 12:49:44 +0200 Subject: [PATCH 77/99] [Logs explorer] Using dockerized package registry in tests (#192064) Closes https://github.com/elastic/kibana/issues/190343. This PR aims to use a dockerized package registry version for testing. In order to test it locally you have to set the value of `FLEET_PACKAGE_REGISTRY_PORT` env var in your terminal, and you also need to have a docker daemon running. For example, you can open a terminal and start the server ``` yarn test:ftr:server --config ./x-pack/test/functional/apps/observability_logs_explorer/config.ts ``` then open a new terminal set the var value and start the runner with the specific test using this configuration ``` export set FLEET_PACKAGE_REGISTRY_PORT=12345 yarn test:ftr:runner --config ./x-pack/test/functional/apps/observability_logs_explorer/config.ts --include ./x-pack/test/functional/apps/observability_logs_explorer/data_source_selector ``` If you want to test again without the dockerized version, you should remove the value of the var ``` unset FLEET_PACKAGE_REGISTRY_PORT ``` --- .../observability_logs_explorer/README.md | 16 ++++++++++ .../common/package_registry_config.yml | 2 ++ .../observability_logs_explorer/config.ts | 30 ++++++++++++++++++- x-pack/test_serverless/README.md | 18 ++++++++++- .../test_serverless/functional/config.base.ts | 6 ++-- .../shared/common/package_registry_config.yml | 2 ++ x-pack/test_serverless/shared/config.base.ts | 25 ++++++++++++++++ 7 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 x-pack/test/functional/apps/observability_logs_explorer/common/package_registry_config.yml create mode 100644 x-pack/test_serverless/shared/common/package_registry_config.yml diff --git a/x-pack/plugins/observability_solution/observability_logs_explorer/README.md b/x-pack/plugins/observability_solution/observability_logs_explorer/README.md index f3546186c1ef3..8f060d48b04f5 100644 --- a/x-pack/plugins/observability_solution/observability_logs_explorer/README.md +++ b/x-pack/plugins/observability_solution/observability_logs_explorer/README.md @@ -37,6 +37,22 @@ yarn test:ftr:runner --config ./x-pack/test_serverless/functional/test_suites/ob yarn test:ftr:runner --config ./x-pack/test_serverless/functional/test_suites/observability/config.ts --include ./x-pack/test_serverless/functional/test_suites/observability/observability_logs_explorer/$1 ``` +### Using dockerized package registry + +For tests using package registry we have enabled a configuration that uses a dockerized lite version to execute the tests in the CI, this will reduce the flakyness of them when calling the real endpoint. + +To be able to run this version locally you must have a docker daemon running in your system and set `FLEET_PACKAGE_REGISTRY_PORT` env var. In order to set this variable execute + +``` +export set FLEET_PACKAGE_REGISTRY_PORT=12345 +``` + +To unset the variable, and run the tests against the real endpoint again, execute + +``` +unset FLEET_PACKAGE_REGISTRY_PORT +``` + ## Checktypes #### Logs Explorer diff --git a/x-pack/test/functional/apps/observability_logs_explorer/common/package_registry_config.yml b/x-pack/test/functional/apps/observability_logs_explorer/common/package_registry_config.yml new file mode 100644 index 0000000000000..1885fa5c2ebe5 --- /dev/null +++ b/x-pack/test/functional/apps/observability_logs_explorer/common/package_registry_config.yml @@ -0,0 +1,2 @@ +package_paths: + - /packages/package-storage diff --git a/x-pack/test/functional/apps/observability_logs_explorer/config.ts b/x-pack/test/functional/apps/observability_logs_explorer/config.ts index 0811f0e2a794e..74c54a9c9e953 100644 --- a/x-pack/test/functional/apps/observability_logs_explorer/config.ts +++ b/x-pack/test/functional/apps/observability_logs_explorer/config.ts @@ -5,8 +5,14 @@ * 2.0. */ -import { FtrConfigProviderContext, GenericFtrProviderContext } from '@kbn/test'; +import { + FtrConfigProviderContext, + GenericFtrProviderContext, + defineDockerServersConfig, +} from '@kbn/test'; import { createLogger, LogLevel, LogsSynthtraceEsClient } from '@kbn/apm-synthtrace'; +import path from 'path'; +import { dockerImage } from '../../../fleet_api_integration/config.base'; import { FtrProviderContext as InheritedFtrProviderContext } from '../../ftr_provider_context'; export type InheritedServices = InheritedFtrProviderContext extends GenericFtrProviderContext< @@ -37,9 +43,31 @@ export default async function createTestConfig({ const functionalConfig = await readConfigFile(require.resolve('../../config.base.js')); const services = functionalConfig.get('services'); + const packageRegistryConfig = path.join(__dirname, './common/package_registry_config.yml'); + const dockerArgs: string[] = ['-v', `${packageRegistryConfig}:/package-registry/config.yml`]; + + /** + * This is used by CI to set the docker registry port + * you can also define this environment variable locally when running tests which + * will spin up a local docker package registry locally for you + * if this is defined it takes precedence over the `packageRegistryOverride` variable + */ + const dockerRegistryPort: string | undefined = process.env.FLEET_PACKAGE_REGISTRY_PORT; + return { ...functionalConfig.getAll(), testFiles: [require.resolve('.')], + dockerServers: defineDockerServersConfig({ + registry: { + enabled: !!dockerRegistryPort, + image: dockerImage, + portInContainer: 8080, + port: dockerRegistryPort, + args: dockerArgs, + waitForLogLine: 'package manifests loaded', + waitForLogLineTimeoutMs: 60 * 2 * 1000, // 2 minutes + }, + }), services: { ...services, logSynthtraceEsClient: (context: InheritedFtrProviderContext) => { diff --git a/x-pack/test_serverless/README.md b/x-pack/test_serverless/README.md index 18bc002d7488d..d7bb3d62d552a 100644 --- a/x-pack/test_serverless/README.md +++ b/x-pack/test_serverless/README.md @@ -259,4 +259,20 @@ describe("my test suite", async function() { }); ``` -If you are running tests from your local against MKI projects, make sure to add `--exclude-tag=skipMKI` to your FTR command. \ No newline at end of file +If you are running tests from your local against MKI projects, make sure to add `--exclude-tag=skipMKI` to your FTR command. + +## Run tests with dockerized package registry + +For tests using package registry we have enabled a configuration that uses a dockerized lite version to execute the tests in the CI, this will reduce the flakyness of them when calling the real endpoint. + +To be able to run this version locally you must have a docker daemon running in your system and set `FLEET_PACKAGE_REGISTRY_PORT` env var. In order to set this variable execute + +``` +export set FLEET_PACKAGE_REGISTRY_PORT=12345 +``` + +To unset the variable, and run the tests against the real endpoint again, execute + +``` +unset FLEET_PACKAGE_REGISTRY_PORT +``` diff --git a/x-pack/test_serverless/functional/config.base.ts b/x-pack/test_serverless/functional/config.base.ts index 22fb253d9896b..826b8bce03885 100644 --- a/x-pack/test_serverless/functional/config.base.ts +++ b/x-pack/test_serverless/functional/config.base.ts @@ -5,10 +5,8 @@ * 2.0. */ -import { resolve } from 'path'; - import { FtrConfigProviderContext } from '@kbn/test'; - +import { resolve } from 'path'; import { pageObjects } from './page_objects'; import { services } from './services'; import type { CreateTestConfigOptions } from '../shared/types'; @@ -16,6 +14,7 @@ import type { CreateTestConfigOptions } from '../shared/types'; export function createTestConfig(options: CreateTestConfigOptions) { return async ({ readConfigFile }: FtrConfigProviderContext) => { const svlSharedConfig = await readConfigFile(require.resolve('../shared/config.base.ts')); + return { ...svlSharedConfig.getAll(), @@ -37,7 +36,6 @@ export function createTestConfig(options: CreateTestConfigOptions) { ], }, testFiles: options.testFiles, - uiSettings: { defaults: { 'accessibility:disableAnimations': true, diff --git a/x-pack/test_serverless/shared/common/package_registry_config.yml b/x-pack/test_serverless/shared/common/package_registry_config.yml new file mode 100644 index 0000000000000..1885fa5c2ebe5 --- /dev/null +++ b/x-pack/test_serverless/shared/common/package_registry_config.yml @@ -0,0 +1,2 @@ +package_paths: + - /packages/package-storage diff --git a/x-pack/test_serverless/shared/config.base.ts b/x-pack/test_serverless/shared/config.base.ts index 099bc6455db3d..1c702f02cff28 100644 --- a/x-pack/test_serverless/shared/config.base.ts +++ b/x-pack/test_serverless/shared/config.base.ts @@ -19,9 +19,23 @@ import { import { CA_CERT_PATH, kibanaDevServiceAccount } from '@kbn/dev-utils'; import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; import { MOCK_IDP_REALM_NAME } from '@kbn/mock-idp-utils'; +import path from 'path'; +import { defineDockerServersConfig } from '@kbn/test'; +import { dockerImage } from '@kbn/test-suites-xpack/fleet_api_integration/config.base'; import { services } from './services'; export default async () => { + const packageRegistryConfig = path.join(__dirname, './common/package_registry_config.yml'); + const dockerArgs: string[] = ['-v', `${packageRegistryConfig}:/package-registry/config.yml`]; + + /** + * This is used by CI to set the docker registry port + * you can also define this environment variable locally when running tests which + * will spin up a local docker package registry locally for you + * if this is defined it takes precedence over the `packageRegistryOverride` variable + */ + const dockerRegistryPort: string | undefined = process.env.FLEET_PACKAGE_REGISTRY_PORT; + const servers = { kibana: { ...kbnTestConfig.getUrlParts(kibanaTestSuperuserServerless), @@ -49,6 +63,17 @@ export default async () => { return { servers, + dockerServers: defineDockerServersConfig({ + registry: { + enabled: !!dockerRegistryPort, + image: dockerImage, + portInContainer: 8080, + port: dockerRegistryPort, + args: dockerArgs, + waitForLogLine: 'package manifests loaded', + waitForLogLineTimeoutMs: 60 * 2 * 1000, // 2 minutes + }, + }), browser: { acceptInsecureCerts: true, }, From 6bef58096f108e7e80e3c45da55928217a39f348 Mon Sep 17 00:00:00 2001 From: Jeramy Soucy Date: Fri, 6 Sep 2024 12:57:19 +0200 Subject: [PATCH 78/99] Serverless custom roles and multiple spaces tests (#191729) ## Summary Implements serverless tests for custom roles and multiple spaces as part of the feature flag test configs. We have implemented them here because the feature flags for custom roles and multiple space are not yet enabled in production. These tests are minimal because when custom roles and custom spaces are eventually be enabled in production, the full stateful test suites should be adapted to deployment agnostic tests if possible. ### API Integration Tests - x-pack/test_serverless/api_integration/test_suites/common/management/multiple_spaces_enabled.ts - x-pack/test_serverless/api_integration/test_suites/common/platform_security/roles_routes_feature_flag.ts ## Functional Tests - x-pack/test_serverless/functional/test_suites/common/platform_security/roles.ts - x-pack/test_serverless/functional/test_suites/common/spaces/multiple_spaces_enabled.ts ## Flaky Test Runners - API Integration Feature Flag tests: https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/6866 - Functional Feature Flag tests: https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/6867 --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../management/multiple_spaces_enabled.ts | 274 ++++++ .../common/platform_security/authorization.ts | 8 +- .../encrypted_saved_objects.ts | 2 - .../roles_routes_feature_flag.ts | 928 +++++++++++++++++- .../observability/config.feature_flags.ts | 8 +- .../observability/index.feature_flags.ts | 1 + .../search/config.feature_flags.ts | 5 +- .../test_suites/search/index.feature_flags.ts | 1 + .../security/config.feature_flags.ts | 7 +- .../security/index.feature_flags.ts | 1 + .../common/platform_security/roles.ts | 101 +- .../common/spaces/multiple_spaces_enabled.ts | 102 ++ .../common/spaces/spaces_selection_enabled.ts | 60 -- .../observability/config.feature_flags.ts | 1 + .../observability/index.feature_flags.ts | 2 +- .../test_suites/search/index.feature_flags.ts | 2 +- .../security/index.feature_flags.ts | 2 +- .../test_serverless/shared/services/index.ts | 5 + .../services/platform_security_utils.ts | 35 + x-pack/test_serverless/tsconfig.json | 1 + 20 files changed, 1387 insertions(+), 159 deletions(-) create mode 100644 x-pack/test_serverless/api_integration/test_suites/common/management/multiple_spaces_enabled.ts create mode 100644 x-pack/test_serverless/functional/test_suites/common/spaces/multiple_spaces_enabled.ts delete mode 100644 x-pack/test_serverless/functional/test_suites/common/spaces/spaces_selection_enabled.ts create mode 100644 x-pack/test_serverless/shared/services/platform_security_utils.ts diff --git a/x-pack/test_serverless/api_integration/test_suites/common/management/multiple_spaces_enabled.ts b/x-pack/test_serverless/api_integration/test_suites/common/management/multiple_spaces_enabled.ts new file mode 100644 index 0000000000000..5466829f30bf0 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/management/multiple_spaces_enabled.ts @@ -0,0 +1,274 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 'expect'; +import { asyncForEach } from '@kbn/std'; +import { SupertestWithRoleScopeType } from '@kbn/test-suites-xpack/api_integration/deployment_agnostic/services'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +// Notes: +// This suite is currently only called from the feature flags test configs, e.g. +// x-pack/test_serverless/api_integration/test_suites/search/config.feature_flags.ts +// Configuration toggle: +// kbnServerArgs: ['--xpack.spaces.maxSpaces=100'], +// +// Initial test coverage limited to CRUD operations and ensuring disabling features/toggling feature visibility is not possible. +// Full coverage of x-pack/test/api_integration/apis/spaces & x-pack/test/spaces_api_integration +// should be converted into a deployment agnostic suite when spaces are +// permanently enabled in serverless. +// +// The route access tests for the spaces APIs in ./spaces.ts should also get updated at that time. + +export default function ({ getService }: FtrProviderContext) { + const svlCommonApi = getService('svlCommonApi'); + const roleScopedSupertest = getService('roleScopedSupertest'); + let supertestWithAdminScope: SupertestWithRoleScopeType; + + async function createSpace(id: string) { + await supertestWithAdminScope + .post('/api/spaces/space') + .send({ + id, + name: id, + disabledFeatures: [], + }) + .expect(200); + } + + async function deleteSpace(id: string) { + await supertestWithAdminScope.delete(`/api/spaces/space/${id}`).expect(204); + } + + describe('spaces', function () { + before(async () => { + supertestWithAdminScope = await roleScopedSupertest.getSupertestWithRoleScope('admin', { + withInternalHeaders: true, + withCustomHeaders: { 'kbn-xsrf': 'true' }, + }); + }); + after(async () => { + // delete any lingering spaces + const { body } = await supertestWithAdminScope.get('/api/spaces/space').send().expect(200); + + const toDelete = (body as Array<{ id: string }>).filter((f) => f.id !== 'default'); + + await asyncForEach(toDelete, async (space) => { + await deleteSpace(space.id); + }); + }); + + describe('Create (POST /api/spaces/space)', () => { + it('should allow us to create a space', async () => { + await supertestWithAdminScope + .post('/api/spaces/space') + .send({ + id: 'custom_space_1', + name: 'custom_space_1', + disabledFeatures: [], + }) + .expect(200); + }); + + it('should not allow us to create a space with disabled features', async () => { + await supertestWithAdminScope + .post('/api/spaces/space') + .send({ + id: 'custom_space_2', + name: 'custom_space_2', + disabledFeatures: ['discover'], + }) + .expect(400); + }); + }); + + describe('Read (GET /api/spaces/space)', () => { + before(async () => { + await createSpace('space_to_get_1'); + await createSpace('space_to_get_2'); + await createSpace('space_to_get_3'); + }); + + after(async () => { + await deleteSpace('space_to_get_1'); + await deleteSpace('space_to_get_2'); + await deleteSpace('space_to_get_3'); + }); + + it('should allow us to get a space', async () => { + await supertestWithAdminScope.get('/api/spaces/space/space_to_get_1').send().expect(200, { + id: 'space_to_get_1', + name: 'space_to_get_1', + disabledFeatures: [], + }); + }); + + it('should allow us to get all spaces', async () => { + const { body } = await supertestWithAdminScope.get('/api/spaces/space').send().expect(200); + + expect(body).toEqual( + expect.arrayContaining([ + { + _reserved: true, + color: '#00bfb3', + description: 'This is your default space!', + disabledFeatures: [], + id: 'default', + name: 'Default', + }, + { id: 'space_to_get_1', name: 'space_to_get_1', disabledFeatures: [] }, + { id: 'space_to_get_2', name: 'space_to_get_2', disabledFeatures: [] }, + { id: 'space_to_get_3', name: 'space_to_get_3', disabledFeatures: [] }, + ]) + ); + }); + }); + + describe('Update (PUT /api/spaces/space)', () => { + before(async () => { + await createSpace('space_to_update'); + }); + + after(async () => { + await deleteSpace('space_to_update'); + }); + + it('should allow us to update a space', async () => { + await supertestWithAdminScope + .put('/api/spaces/space/space_to_update') + .send({ + id: 'space_to_update', + name: 'some new name', + initials: 'SN', + disabledFeatures: [], + }) + .expect(200); + + await supertestWithAdminScope.get('/api/spaces/space/space_to_update').send().expect(200, { + id: 'space_to_update', + name: 'some new name', + initials: 'SN', + disabledFeatures: [], + }); + }); + + it('should not allow us to update a space with disabled features', async () => { + await supertestWithAdminScope + .put('/api/spaces/space/space_to_update') + .send({ + id: 'space_to_update', + name: 'some new name', + initials: 'SN', + disabledFeatures: ['discover'], + }) + .expect(400); + }); + }); + + describe('Delete (DELETE /api/spaces/space)', () => { + it('should allow us to delete a space', async () => { + await createSpace('space_to_delete'); + + await supertestWithAdminScope.delete(`/api/spaces/space/space_to_delete`).expect(204); + }); + }); + + describe('Get active space (GET /internal/spaces/_active_space)', () => { + before(async () => { + await createSpace('foo-space'); + }); + + after(async () => { + await deleteSpace('foo-space'); + }); + + it('returns the default space', async () => { + const response = await supertestWithAdminScope + .get('/internal/spaces/_active_space') + .expect(200); + + const { id, name, _reserved } = response.body; + expect({ id, name, _reserved }).toEqual({ + id: 'default', + name: 'Default', + _reserved: true, + }); + }); + + it('returns the default space when explicitly referenced', async () => { + const response = await supertestWithAdminScope + .get('/s/default/internal/spaces/_active_space') + .expect(200); + + const { id, name, _reserved } = response.body; + expect({ id, name, _reserved }).toEqual({ + id: 'default', + name: 'Default', + _reserved: true, + }); + }); + + it('returns the foo space', async () => { + await supertestWithAdminScope + .get('/s/foo-space/internal/spaces/_active_space') + .expect(200, { + id: 'foo-space', + name: 'foo-space', + disabledFeatures: [], + }); + }); + + it('returns 404 when the space is not found', async () => { + await supertestWithAdminScope + .get('/s/not-found-space/internal/spaces/_active_space') + .expect(404, { + statusCode: 404, + error: 'Not Found', + message: 'Saved object [space/not-found-space] not found', + }); + }); + }); + + // These tests just test access to API endpoints + // They will be included in deployment agnostic testing once spaces + // are enabled in production. + describe(`Access`, () => { + it('#copyToSpace', async () => { + const { body, status } = await supertestWithAdminScope.post( + '/api/spaces/_copy_saved_objects' + ); + svlCommonApi.assertResponseStatusCode(400, status, body); + }); + it('#resolveCopyToSpaceErrors', async () => { + const { body, status } = await supertestWithAdminScope.post( + '/api/spaces/_resolve_copy_saved_objects_errors' + ); + svlCommonApi.assertResponseStatusCode(400, status, body); + }); + it('#updateObjectsSpaces', async () => { + const { body, status } = await supertestWithAdminScope.post( + '/api/spaces/_update_objects_spaces' + ); + svlCommonApi.assertResponseStatusCode(400, status, body); + }); + it('#getShareableReferences', async () => { + const { body, status } = await supertestWithAdminScope + .post('/api/spaces/_get_shareable_references') + .send({ + objects: [{ type: 'a', id: 'a' }], + }); + svlCommonApi.assertResponseStatusCode(200, status, body); + }); + it('#disableLegacyUrlAliases', async () => { + const { body, status } = await supertestWithAdminScope.post( + '/api/spaces/_disable_legacy_url_aliases' + ); + // without a request body we would normally a 400 bad request if the endpoint was registered + svlCommonApi.assertApiNotFound(body, status); + }); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts index 95277f9ea8d79..71b58821f3a50 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts @@ -64,7 +64,7 @@ export default function ({ getService }: FtrProviderContext) { it('create/update roleAuthc', async () => { const { body, status } = await supertestWithoutAuth - .put('/api/security/roleAuthc/test') + .put('/api/security/role/test') .set(svlCommonApi.getInternalRequestHeader()) .set(roleAuthc.apiKeyHeader); svlCommonApi.assertApiNotFound(body, status); @@ -72,7 +72,7 @@ export default function ({ getService }: FtrProviderContext) { it('get roleAuthc', async () => { const { body, status } = await supertestWithoutAuth - .get('/api/security/roleAuthc/superuser') + .get('/api/security/role/superuser') .set(svlCommonApi.getInternalRequestHeader()) .set(roleAuthc.apiKeyHeader); svlCommonApi.assertApiNotFound(body, status); @@ -80,7 +80,7 @@ export default function ({ getService }: FtrProviderContext) { it('get all roles', async () => { const { body, status } = await supertestWithoutAuth - .get('/api/security/roleAuthc') + .get('/api/security/role') .set(svlCommonApi.getInternalRequestHeader()) .set(roleAuthc.apiKeyHeader); svlCommonApi.assertApiNotFound(body, status); @@ -88,7 +88,7 @@ export default function ({ getService }: FtrProviderContext) { it('delete roleAuthc', async () => { const { body, status } = await supertestWithoutAuth - .delete('/api/security/roleAuthc/superuser') + .delete('/api/security/role/superuser') .set(svlCommonApi.getInternalRequestHeader()) .set(roleAuthc.apiKeyHeader); svlCommonApi.assertApiNotFound(body, status); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/encrypted_saved_objects.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/encrypted_saved_objects.ts index 51a0d3f03be8f..d392fce85df02 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/encrypted_saved_objects.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/encrypted_saved_objects.ts @@ -32,9 +32,7 @@ export default function ({ getService }: FtrProviderContext) { ({ body, status } = await supertestWithoutAuth .post('/api/encrypted_saved_objects/_rotate_key') - // .set(internalReqHeader) .set(roleAuthc.apiKeyHeader)); - // svlCommonApi.assertApiNotFound(body, status); // expect a rejection because we're not using the internal header expect(body).toEqual({ statusCode: 400, diff --git a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/roles_routes_feature_flag.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/roles_routes_feature_flag.ts index eb20cbff7826a..6d5a6f93b1187 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/roles_routes_feature_flag.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/roles_routes_feature_flag.ts @@ -5,57 +5,919 @@ * 2.0. */ +import expect from '@kbn/expect'; +import type { Role } from '@kbn/security-plugin-types-common'; +import { SupertestWithRoleScopeType } from '@kbn/test-suites-xpack/api_integration/deployment_agnostic/services'; import { FtrProviderContext } from '../../../ftr_provider_context'; +// Notes: +// Test coverage comes from stateful test suite: x-pack/test/api_integration/apis/security/roles.ts +// It has been modified to work for serverless by removing invalid options (run_as, allow_restricted_indices, etc). +// +// Note: this suite is currently only called from the feature flags test configs, e.g. +// x-pack/test_serverless/api_integration/test_suites/search/config.feature_flags.ts +// +// This suite should be converted into a deployment agnostic suite when the native roles +// feature flags are enabled permanently in serverless. Additionally, the route access tests +// for the roles APIs in authorization.ts should also get updated at that time. +// kbnServerArgs: ['--xpack.security.roleManagementEnabled=true'], +// esServerArgs: ['xpack.security.authc.native_roles.enabled=true'], + export default function ({ getService }: FtrProviderContext) { - const svlCommonApi = getService('svlCommonApi'); - const supertest = getService('supertest'); + const platformSecurityUtils = getService('platformSecurityUtils'); + const roleScopedSupertest = getService('roleScopedSupertest'); + let supertestWithAdminScope: SupertestWithRoleScopeType; + const es = getService('es'); describe('security', function () { - describe('route access', () => { - describe('roles', () => { - describe('enabled', () => { - it('get role', async () => { - const { body, status } = await supertest - .get('/api/security/role/superuser') - .set(svlCommonApi.getInternalRequestHeader()); - svlCommonApi.assertResponseStatusCode(200, status, body); + describe('Roles', () => { + before(async () => { + supertestWithAdminScope = await roleScopedSupertest.getSupertestWithRoleScope('admin', { + withInternalHeaders: true, + withCustomHeaders: { 'kbn-xsrf': 'true' }, + }); + }); + after(async () => { + await platformSecurityUtils.clearAllRoles(); + }); + + describe('Create Role', () => { + it('should allow us to create an empty role', async () => { + await supertestWithAdminScope.put('/api/security/role/empty_role').send({}).expect(204); + }); + + it('should create a role with kibana and elasticsearch privileges', async () => { + await supertestWithAdminScope + .put('/api/security/role/role_with_privileges') + .send({ + metadata: { + foo: 'test-metadata', + }, + elasticsearch: { + cluster: ['manage'], + indices: [ + { + names: ['logstash-*'], + privileges: ['read', 'view_index_metadata'], + }, + ], + }, + kibana: [ + { + base: ['read'], + }, + { + feature: { + dashboard: ['read'], + discover: ['all'], + ml: ['all'], + }, + spaces: ['marketing', 'sales'], + }, + ], + }) + .expect(204); + + const role = await es.security.getRole({ name: 'role_with_privileges' }); + expect(role).to.eql({ + role_with_privileges: { + cluster: ['manage'], + indices: [ + { + names: ['logstash-*'], + privileges: ['read', 'view_index_metadata'], + allow_restricted_indices: false, + }, + ], + applications: [ + { + application: 'kibana-.kibana', + privileges: ['read'], + resources: ['*'], + }, + { + application: 'kibana-.kibana', + privileges: ['feature_dashboard.read', 'feature_discover.all', 'feature_ml.all'], + resources: ['space:marketing', 'space:sales'], + }, + ], + metadata: { + foo: 'test-metadata', + }, + run_as: [], + transient_metadata: { + enabled: true, + }, + }, + }); + }); + + it(`should create a role with kibana and FLS/DLS elasticsearch privileges`, async () => { + await supertestWithAdminScope + .put('/api/security/role/role_with_privileges_dls_fls') + .send({ + metadata: { + foo: 'test-metadata', + }, + elasticsearch: { + cluster: ['manage'], + indices: [ + { + field_security: { + grant: ['*'], + except: ['geo.*'], + }, + names: ['logstash-*'], + privileges: ['read', 'view_index_metadata'], + query: `{ "match": { "geo.src": "CN" } }`, + }, + ], + }, + }) + .expect(204); + }); + + // serverless only (stateful will allow) + it(`should not create a role with 'run as' privileges`, async () => { + await supertestWithAdminScope + .put('/api/security/role/role_with_privileges') + .send({ + metadata: { + foo: 'test-metadata', + }, + elasticsearch: { + cluster: ['manage'], + indices: [ + { + names: ['logstash-*'], + privileges: ['read', 'view_index_metadata'], + }, + ], + run_as: ['admin'], + }, + kibana: [ + { + base: ['read'], + }, + { + feature: { + dashboard: ['read'], + discover: ['all'], + ml: ['all'], + }, + spaces: ['marketing', 'sales'], + }, + ], + }) + .expect(400); + }); + + // serverless only (stateful will allow) + it(`should not create a role with remote cluster privileges`, async () => { + await supertestWithAdminScope + .put('/api/security/role/role_with_privileges') + .send({ + metadata: { + foo: 'test-metadata', + }, + elasticsearch: { + cluster: ['manage'], + indices: [ + { + names: ['logstash-*'], + privileges: ['read', 'view_index_metadata'], + }, + ], + remote_cluster: [ + { + clusters: ['remote_cluster1'], + privileges: ['monitor_enrich'], + }, + ], + }, + kibana: [ + { + base: ['read'], + }, + { + feature: { + dashboard: ['read'], + discover: ['all'], + ml: ['all'], + }, + spaces: ['marketing', 'sales'], + }, + ], + }) + .expect(400); + }); + + // serverless only (stateful will allow) + it(`should not create a role with remote index privileges`, async () => { + await supertestWithAdminScope + .put('/api/security/role/role_with_privileges') + .send({ + metadata: { + foo: 'test-metadata', + }, + elasticsearch: { + cluster: ['manage'], + indices: [ + { + names: ['logstash-*'], + privileges: ['read', 'view_index_metadata'], + }, + ], + remote_indices: [ + { + clusters: ['remote_cluster1'], + names: ['remote_index1', 'remote_index2'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + base: ['read'], + }, + { + feature: { + dashboard: ['read'], + discover: ['all'], + ml: ['all'], + }, + spaces: ['marketing', 'sales'], + }, + ], + }) + .expect(400); + }); + + describe('with the createOnly option enabled', () => { + it('should fail when role already exists', async () => { + await es.security.putRole({ + name: 'test_role', + body: { + cluster: ['monitor'], + indices: [ + { + names: ['beats-*'], + privileges: ['write'], + }, + ], + }, + }); + + await supertestWithAdminScope + .put('/api/security/role/test_role?createOnly=true') + .send({}) + .expect(409); }); - it('get all roles', async () => { - const { body, status } = await supertest - .get('/api/security/role') - .set(svlCommonApi.getInternalRequestHeader()); - svlCommonApi.assertResponseStatusCode(200, status, body); + it('should succeed when role does not exist', async () => { + await supertestWithAdminScope + .put('/api/security/role/new_role?createOnly=true') + .send({}) + .expect(204); }); }); + }); - describe('moved', () => { - it('delete role', async () => { - const { body, status } = await supertest - .delete('/api/security/role/superuser') - .set(svlCommonApi.getInternalRequestHeader()); + describe('Read Role', () => { + it('should get roles', async () => { + await es.security.putRole({ + name: 'role_to_get', + body: { + cluster: ['manage'], + indices: [ + { + names: ['logstash-*'], + privileges: ['read', 'view_index_metadata'], + }, + ], + applications: [ + { + application: 'kibana-.kibana', + privileges: ['read'], + resources: ['*'], + }, + { + application: 'kibana-.kibana', + privileges: ['feature_dashboard.read', 'feature_discover.all', 'feature_ml.all'], + resources: ['space:marketing', 'space:sales'], + }, + { + application: 'apm', + privileges: ['apm-privilege'], + resources: ['*'], + }, + ], + metadata: { + foo: 'test-metadata', + }, + transient_metadata: { + enabled: true, + }, + }, + }); - svlCommonApi.assertResponseStatusCode(410, status, body); + await supertestWithAdminScope.get('/api/security/role/role_to_get').expect(200, { + name: 'role_to_get', + metadata: { + foo: 'test-metadata', + }, + transient_metadata: { enabled: true }, + elasticsearch: { + cluster: ['manage'], + indices: [ + { + names: ['logstash-*'], + privileges: ['read', 'view_index_metadata'], + allow_restricted_indices: false, + }, + ], + run_as: [], + }, + kibana: [ + { + base: ['read'], + feature: {}, + spaces: ['*'], + }, + { + base: [], + feature: { + dashboard: ['read'], + discover: ['all'], + ml: ['all'], + }, + spaces: ['marketing', 'sales'], + }, + ], + + _transform_error: [], + _unrecognized_applications: ['apm'], + }); + }); + + it('should get roles by space id', async () => { + await es.security.putRole({ + name: 'space_role_not_to_get', + body: { + cluster: ['manage'], + indices: [ + { + names: ['logstash-*'], + privileges: ['read', 'view_index_metadata'], + }, + ], + applications: [ + { + application: 'kibana-.kibana', + privileges: ['feature_dashboard.read', 'feature_discover.all', 'feature_ml.all'], + resources: ['space:marketing', 'space:sales'], + }, + ], + metadata: { + foo: 'test-metadata', + }, + transient_metadata: { + enabled: true, + }, + }, + }); + + await es.security.putRole({ + name: 'space_role_to_get', + body: { + cluster: ['manage'], + indices: [ + { + names: ['logstash-*'], + privileges: ['read', 'view_index_metadata'], + }, + ], + applications: [ + { + application: 'kibana-.kibana', + privileges: ['feature_dashboard.read', 'feature_discover.all', 'feature_ml.all'], + resources: ['space:engineering', 'space:sales'], + }, + ], + metadata: { + foo: 'test-metadata', + }, + transient_metadata: { + enabled: true, + }, + }, }); - it('create/update role', async () => { - const role = { + await supertestWithAdminScope + .get('/internal/security/roles/engineering') + .expect(200) + .expect((res: { body: Role[] }) => { + const roles = res.body; + expect(roles).to.be.an('array'); + + const success = roles.every((role) => { + return ( + role.name !== 'space_role_not_to_get' && + role.kibana.some((privilege) => { + return ( + privilege.spaces.includes('*') || privilege.spaces.includes('engineering') + ); + }) + ); + }); + + const expectedRole = roles.find((role) => role.name === 'space_role_to_get'); + + expect(success).to.be(true); + expect(expectedRole).to.be.an('object'); + }); + }); + }); + + describe('Update Role', () => { + it('should update a role with elasticsearch, kibana and other applications privileges', async () => { + await es.security.putRole({ + name: 'role_to_update', + body: { + cluster: ['monitor'], + indices: [ + { + names: ['beats-*'], + privileges: ['write'], + }, + ], + applications: [ + { + application: 'kibana-.kibana', + privileges: ['read'], + resources: ['*'], + }, + { + application: 'apm', + privileges: ['apm-privilege'], + resources: ['*'], + }, + ], + metadata: { + bar: 'old-metadata', + }, + }, + }); + + await supertestWithAdminScope + .put('/api/security/role/role_to_update') + .send({ + metadata: { + foo: 'test-metadata', + }, elasticsearch: { - cluster: [], - indices: [{ names: ['test'], privileges: ['read'] }], - run_as: [], + cluster: ['manage'], + indices: [ + { + names: ['logstash-*'], + privileges: ['read', 'view_index_metadata'], + }, + ], }, - kibana: [], - }; + kibana: [ + { + feature: { + dashboard: ['read'], + dev_tools: ['all'], + }, + spaces: ['*'], + }, + { + base: ['all'], + spaces: ['marketing', 'sales'], + }, + ], + }) + .expect(204); - const { body, status } = await supertest - .put('/api/security/role/myRole') - .send(role) - .set(svlCommonApi.getInternalRequestHeader()); + const role = await es.security.getRole({ name: 'role_to_update' }); + expect(role).to.eql({ + role_to_update: { + cluster: ['manage'], + indices: [ + { + names: ['logstash-*'], + privileges: ['read', 'view_index_metadata'], + allow_restricted_indices: false, + }, + ], + applications: [ + { + application: 'kibana-.kibana', + privileges: ['feature_dashboard.read', 'feature_dev_tools.all'], + resources: ['*'], + }, + { + application: 'kibana-.kibana', + privileges: ['space_all'], + resources: ['space:marketing', 'space:sales'], + }, + { + application: 'apm', + privileges: ['apm-privilege'], + resources: ['*'], + }, + ], + metadata: { + foo: 'test-metadata', + }, + run_as: [], + transient_metadata: { + enabled: true, + }, + }, + }); + }); - svlCommonApi.assertResponseStatusCode(410, status, body); + it(`should update a role adding DLS and FLS privileges`, async () => { + await es.security.putRole({ + name: 'role_to_update_with_dls_fls', + body: { + cluster: ['monitor'], + indices: [ + { + names: ['beats-*'], + privileges: ['write'], + }, + ], + }, }); + + await supertestWithAdminScope + .put('/api/security/role/role_to_update_with_dls_fls') + .send({ + elasticsearch: { + cluster: ['manage'], + indices: [ + { + field_security: { + grant: ['*'], + except: ['geo.*'], + }, + names: ['logstash-*'], + privileges: ['read'], + query: `{ "match": { "geo.src": "CN" } }`, + }, + ], + }, + }) + .expect(204); + + const role = await es.security.getRole({ name: 'role_to_update_with_dls_fls' }); + + expect(role.role_to_update_with_dls_fls.cluster).to.eql(['manage']); + expect(role.role_to_update_with_dls_fls.indices[0].names).to.eql(['logstash-*']); + expect(role.role_to_update_with_dls_fls.indices[0].query).to.eql( + `{ "match": { "geo.src": "CN" } }` + ); + }); + + // serverless only (stateful will allow) + it(`should not update a role with 'run as' privileges`, async () => { + await es.security.putRole({ + name: 'role_to_update', + body: { + cluster: ['monitor'], + indices: [ + { + names: ['beats-*'], + privileges: ['write'], + }, + ], + applications: [ + { + application: 'kibana-.kibana', + privileges: ['read'], + resources: ['*'], + }, + { + application: 'apm', + privileges: ['apm-privilege'], + resources: ['*'], + }, + ], + metadata: { + bar: 'old-metadata', + }, + }, + }); + + await supertestWithAdminScope + .put('/api/security/role/role_to_update') + .send({ + metadata: { + foo: 'test-metadata', + }, + elasticsearch: { + cluster: ['manage'], + indices: [ + { + names: ['logstash-*'], + privileges: ['read', 'view_index_metadata'], + }, + ], + run_as: ['admin'], + }, + kibana: [ + { + feature: { + dashboard: ['read'], + dev_tools: ['all'], + }, + spaces: ['*'], + }, + { + base: ['all'], + spaces: ['marketing', 'sales'], + }, + ], + }) + .expect(400); + + const role = await es.security.getRole({ name: 'role_to_update' }); + expect(role).to.eql({ + role_to_update: { + cluster: ['monitor'], + indices: [ + { + names: ['beats-*'], + privileges: ['write'], + allow_restricted_indices: false, + }, + ], + applications: [ + { + application: 'kibana-.kibana', + privileges: ['read'], + resources: ['*'], + }, + { + application: 'apm', + privileges: ['apm-privilege'], + resources: ['*'], + }, + ], + metadata: { + bar: 'old-metadata', + }, + run_as: [], + transient_metadata: { + enabled: true, + }, + }, + }); + }); + + // serverless only (stateful will allow) + it(`should not update a role with remote cluster privileges`, async () => { + await es.security.putRole({ + name: 'role_to_update', + body: { + cluster: ['monitor'], + indices: [ + { + names: ['beats-*'], + privileges: ['write'], + }, + ], + applications: [ + { + application: 'kibana-.kibana', + privileges: ['read'], + resources: ['*'], + }, + { + application: 'apm', + privileges: ['apm-privilege'], + resources: ['*'], + }, + ], + metadata: { + bar: 'old-metadata', + }, + }, + }); + + await supertestWithAdminScope + .put('/api/security/role/role_to_update') + .send({ + metadata: { + foo: 'test-metadata', + }, + elasticsearch: { + cluster: ['manage'], + indices: [ + { + names: ['logstash-*'], + privileges: ['read', 'view_index_metadata'], + }, + ], + remote_cluster: [ + { + clusters: ['remote_cluster1'], + privileges: ['monitor_enrich'], + }, + ], + }, + kibana: [ + { + feature: { + dashboard: ['read'], + dev_tools: ['all'], + }, + spaces: ['*'], + }, + { + base: ['all'], + spaces: ['marketing', 'sales'], + }, + ], + }) + .expect(400); + + const role = await es.security.getRole({ name: 'role_to_update' }); + expect(role).to.eql({ + role_to_update: { + cluster: ['monitor'], + indices: [ + { + names: ['beats-*'], + privileges: ['write'], + allow_restricted_indices: false, + }, + ], + applications: [ + { + application: 'kibana-.kibana', + privileges: ['read'], + resources: ['*'], + }, + { + application: 'apm', + privileges: ['apm-privilege'], + resources: ['*'], + }, + ], + metadata: { + bar: 'old-metadata', + }, + run_as: [], + transient_metadata: { + enabled: true, + }, + }, + }); + }); + + // serverless only (stateful will allow) + it(`should not update a role with remote index privileges`, async () => { + await es.security.putRole({ + name: 'role_to_update', + body: { + cluster: ['monitor'], + indices: [ + { + names: ['beats-*'], + privileges: ['write'], + }, + ], + applications: [ + { + application: 'kibana-.kibana', + privileges: ['read'], + resources: ['*'], + }, + { + application: 'apm', + privileges: ['apm-privilege'], + resources: ['*'], + }, + ], + metadata: { + bar: 'old-metadata', + }, + }, + }); + + await supertestWithAdminScope + .put('/api/security/role/role_to_update') + .send({ + metadata: { + foo: 'test-metadata', + }, + elasticsearch: { + cluster: ['manage'], + indices: [ + { + names: ['logstash-*'], + privileges: ['read', 'view_index_metadata'], + }, + ], + remote_indices: [ + { + clusters: ['remote_cluster1'], + names: ['remote_index1', 'remote_index2'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + dashboard: ['read'], + dev_tools: ['all'], + }, + spaces: ['*'], + }, + { + base: ['all'], + spaces: ['marketing', 'sales'], + }, + ], + }) + .expect(400); + + const role = await es.security.getRole({ name: 'role_to_update' }); + expect(role).to.eql({ + role_to_update: { + cluster: ['monitor'], + indices: [ + { + names: ['beats-*'], + privileges: ['write'], + allow_restricted_indices: false, + }, + ], + applications: [ + { + application: 'kibana-.kibana', + privileges: ['read'], + resources: ['*'], + }, + { + application: 'apm', + privileges: ['apm-privilege'], + resources: ['*'], + }, + ], + metadata: { + bar: 'old-metadata', + }, + run_as: [], + transient_metadata: { + enabled: true, + }, + }, + }); + }); + }); + + describe('Delete Role', () => { + it('should delete an existing role', async () => { + await es.security.putRole({ + name: 'role_to_delete', + body: { + cluster: ['monitor'], + indices: [ + { + names: ['beats-*'], + privileges: ['write'], + }, + ], + applications: [ + { + application: 'kibana-.kibana', + privileges: ['read'], + resources: ['*'], + }, + { + application: 'apm', + privileges: ['apm-privilege'], + resources: ['*'], + }, + ], + metadata: { + bar: 'old-metadata', + }, + }, + }); + await supertestWithAdminScope.delete('/api/security/role/role_to_delete').expect(204); + + const deletedRole = await es.security.getRole( + { name: 'role_to_delete' }, + { ignore: [404] } + ); + expect(deletedRole).to.eql({}); }); }); }); diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/config.feature_flags.ts b/x-pack/test_serverless/api_integration/test_suites/observability/config.feature_flags.ts index 07ddcfd248cc2..20724f4f9ae16 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/config.feature_flags.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/config.feature_flags.ts @@ -20,11 +20,15 @@ export default createTestConfig({ suiteTags: { exclude: ['skipSvlOblt'] }, services, // add feature flags - kbnServerArgs: ['--xpack.infra.enabled=true', '--xpack.security.roleManagementEnabled=true'], + kbnServerArgs: [ + '--xpack.infra.enabled=true', + '--xpack.security.roleManagementEnabled=true', // enables custom roles + `--xpack.spaces.maxSpaces=100`, // enables spaces UI capabilities + ], // load tests in the index file testFiles: [require.resolve('./index.feature_flags.ts')], // include settings from project controller // https://github.com/elastic/project-controller/blob/main/internal/project/observability/config/elasticsearch.yml - esServerArgs: ['xpack.ml.dfa.enabled=false'], + esServerArgs: ['xpack.ml.dfa.enabled=false', 'xpack.security.authc.native_roles.enabled=true'], }); diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/index.feature_flags.ts b/x-pack/test_serverless/api_integration/test_suites/observability/index.feature_flags.ts index dfd398fc360d0..44ac3675266f7 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/index.feature_flags.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/index.feature_flags.ts @@ -13,5 +13,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./infra')); loadTestFile(require.resolve('./platform_security')); loadTestFile(require.resolve('../common/platform_security/roles_routes_feature_flag.ts')); + loadTestFile(require.resolve('../common/management/multiple_spaces_enabled.ts')); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/search/config.feature_flags.ts b/x-pack/test_serverless/api_integration/test_suites/search/config.feature_flags.ts index 3126619ae60ee..09de0f17e6b63 100644 --- a/x-pack/test_serverless/api_integration/test_suites/search/config.feature_flags.ts +++ b/x-pack/test_serverless/api_integration/test_suites/search/config.feature_flags.ts @@ -19,7 +19,8 @@ export default createTestConfig({ suiteTags: { exclude: ['skipSvlSearch'] }, // add feature flags kbnServerArgs: [ - '--xpack.security.roleManagementEnabled=true', + '--xpack.security.roleManagementEnabled=true', // enables custom roles + `--xpack.spaces.maxSpaces=100`, // enables spaces UI capabilities `--xpack.searchIndices.enabled=true`, // global empty state FF ], // load tests in the index file @@ -27,5 +28,5 @@ export default createTestConfig({ // include settings from project controller // https://github.com/elastic/project-controller/blob/main/internal/project/esproject/config/elasticsearch.yml - esServerArgs: [], + esServerArgs: ['xpack.security.authc.native_roles.enabled=true'], }); diff --git a/x-pack/test_serverless/api_integration/test_suites/search/index.feature_flags.ts b/x-pack/test_serverless/api_integration/test_suites/search/index.feature_flags.ts index a4a99f1e42641..acd435d9d29ae 100644 --- a/x-pack/test_serverless/api_integration/test_suites/search/index.feature_flags.ts +++ b/x-pack/test_serverless/api_integration/test_suites/search/index.feature_flags.ts @@ -12,5 +12,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./search_indices')); loadTestFile(require.resolve('./platform_security')); loadTestFile(require.resolve('../common/platform_security/roles_routes_feature_flag.ts')); + loadTestFile(require.resolve('../common/management/multiple_spaces_enabled.ts')); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/security/config.feature_flags.ts b/x-pack/test_serverless/api_integration/test_suites/security/config.feature_flags.ts index beaa65c5964d5..eb6270bab7ce1 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/config.feature_flags.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/config.feature_flags.ts @@ -18,11 +18,14 @@ export default createTestConfig({ }, suiteTags: { exclude: ['skipSvlSec'] }, // add feature flags - kbnServerArgs: ['--xpack.security.roleManagementEnabled=true'], + kbnServerArgs: [ + '--xpack.security.roleManagementEnabled=true', // enables custom roles + `--xpack.spaces.maxSpaces=100`, // enables spaces UI capabilities + ], // load tests in the index file testFiles: [require.resolve('./index.feature_flags.ts')], // include settings from project controller // https://github.com/elastic/project-controller/blob/main/internal/project/security/config/elasticsearch.yml - esServerArgs: ['xpack.ml.nlp.enabled=true'], + esServerArgs: ['xpack.ml.nlp.enabled=true', 'xpack.security.authc.native_roles.enabled=true'], }); diff --git a/x-pack/test_serverless/api_integration/test_suites/security/index.feature_flags.ts b/x-pack/test_serverless/api_integration/test_suites/security/index.feature_flags.ts index f929d3e64c6bc..5c591f3213149 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/index.feature_flags.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/index.feature_flags.ts @@ -11,5 +11,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('Serverless security API - feature flags', function () { loadTestFile(require.resolve('./platform_security')); loadTestFile(require.resolve('../common/platform_security/roles_routes_feature_flag.ts')); + loadTestFile(require.resolve('../common/management/multiple_spaces_enabled.ts')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/common/platform_security/roles.ts b/x-pack/test_serverless/functional/test_suites/common/platform_security/roles.ts index 8f70e48b7191d..a57f82f158ebf 100644 --- a/x-pack/test_serverless/functional/test_suites/common/platform_security/roles.ts +++ b/x-pack/test_serverless/functional/test_suites/common/platform_security/roles.ts @@ -5,72 +5,71 @@ * 2.0. */ import expect from '@kbn/expect'; -import { Client } from '@elastic/elasticsearch'; -import { ToolingLog } from '@kbn/tooling-log'; import { FtrProviderContext } from '../../../ftr_provider_context'; -async function clearAllRoles(esClient: Client, logger: ToolingLog) { - const existingRoles = await esClient.security.getRole(); - const esRolesNames = Object.entries(existingRoles) - .filter(([roleName, esRole]) => { - return !esRole.metadata?._reserved; - }) - .map(([roleName]) => roleName); - - if (esRolesNames.length > 0) { - await Promise.all( - esRolesNames.map(async (roleName) => { - await esClient.security.deleteRole({ name: roleName }); - }) - ); - } else { - logger.debug('No Roles to delete.'); - } -} +// Note: this suite is currently only called from the feature flags test config: +// x-pack/test_serverless/functional/test_suites/search/config.feature_flags.ts +// This can be moved into the common config groups once custom roles are enabled +// permanently in serverless. export default ({ getPageObjects, getService }: FtrProviderContext) => { const testSubjects = getService('testSubjects'); const pageObjects = getPageObjects(['common', 'svlCommonPage', 'svlManagementPage', 'security']); const browser = getService('browser'); - const es = getService('es'); - const log = getService('log'); + const platformSecurityUtils = getService('platformSecurityUtils'); describe('Roles', function () { - before(async () => { - await pageObjects.svlCommonPage.loginAsAdmin(); - await pageObjects.common.navigateToApp('management'); - await pageObjects.svlManagementPage.assertRoleManagementCardExists(); - await pageObjects.svlManagementPage.clickRoleManagementCard(); - const url = await browser.getCurrentUrl(); - expect(url).to.contain('/management/security/roles'); - }); + describe('as Viewer', () => { + before(async () => { + await pageObjects.svlCommonPage.loginAsViewer(); + await pageObjects.common.navigateToApp('management'); + }); - after(async () => { - await clearAllRoles(es, log); + it('should not display the roles management card', async () => { + await pageObjects.svlManagementPage.assertRoleManagementCardDoesNotExist(); + }); }); - it('should not display reserved roles', async () => { - const table = await testSubjects.find('rolesTable'); - const tableContent = await table.getVisibleText(); - expect(tableContent).to.contain('No custom roles to show'); - }); + describe('as Admin', () => { + before(async () => { + await pageObjects.svlCommonPage.loginAsAdmin(); + await pageObjects.common.navigateToApp('management'); + await pageObjects.svlManagementPage.assertRoleManagementCardExists(); + await pageObjects.svlManagementPage.clickRoleManagementCard(); + const url = await browser.getCurrentUrl(); + expect(url).to.contain('/management/security/roles'); + }); + + after(async () => { + await platformSecurityUtils.clearAllRoles(); + }); - it('should create and only display custom roles', async () => { - const customRole = 'serverlesscustomrole'; - await pageObjects.security.addRole(customRole, { - elasticsearch: { - indices: [ - { - names: ['dlstest'], - privileges: ['read', 'view_index_metadata'], - }, - ], - }, + it('should not display reserved roles', async () => { + const table = await testSubjects.find('rolesTable'); + const tableContent = await table.getVisibleText(); + expect(tableContent).to.contain('No custom roles to show'); }); - const table = await testSubjects.find('rolesTable'); - const tableContent = await table.getVisibleText(); - expect(tableContent).to.contain(customRole); + it('should create and only display custom roles', async () => { + const customRole = 'serverless-custom-role'; + await pageObjects.security.addRole(customRole, { + elasticsearch: { + indices: [ + { + names: ['dlstest'], + privileges: ['read', 'view_index_metadata'], + }, + ], + }, + }); + + const rows = await testSubjects.findAll('roleRow'); + expect(rows.length).equal(1); + const cells = await rows[0].findAllByClassName('euiTableRowCell'); + expect(cells.length).greaterThan(1); + const cellContent = await cells[0].getVisibleText(); + expect(cellContent).to.contain(customRole); + }); }); }); }; diff --git a/x-pack/test_serverless/functional/test_suites/common/spaces/multiple_spaces_enabled.ts b/x-pack/test_serverless/functional/test_suites/common/spaces/multiple_spaces_enabled.ts new file mode 100644 index 0000000000000..84c7291e6e7ad --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/spaces/multiple_spaces_enabled.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. + */ + +// Note: this suite is currently only called from the feature flags test config: +// x-pack/test_serverless/functional/test_suites/search/config.feature_flags.ts +// These tests can be moved to the appropriate test file (spaces_selection, +// spaces_management) once multiple spaces are permanently enabled in production. + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getPageObject, getService }: FtrProviderContext) { + const svlCommon = getPageObject('common'); + const svlCommonPage = getPageObject('svlCommonPage'); + const svlCommonNavigation = getService('svlCommonNavigation'); + const testSubjects = getService('testSubjects'); + + describe('spaces', function () { + describe('selection', function () { + describe('as Viewer', function () { + before(async () => { + await svlCommonPage.loginAsViewer(); + }); + + it('displays the space selection menu in header', async () => { + await svlCommonNavigation.navigateToKibanaHome(); + await svlCommonPage.assertProjectHeaderExists(); + + await testSubjects.existOrFail('spacesNavSelector'); + }); + + it(`does not display the manage button in the space selection menu`, async () => { + await svlCommonNavigation.navigateToKibanaHome(); + await svlCommonPage.assertProjectHeaderExists(); + await testSubjects.click('spacesNavSelector'); + await testSubjects.missingOrFail('manageSpaces'); + }); + }); + + describe('as Admin', function () { + before(async () => { + await svlCommonPage.loginAsAdmin(); + }); + + it('displays the space selection menu in header', async () => { + await svlCommonNavigation.navigateToKibanaHome(); + await svlCommonPage.assertProjectHeaderExists(); + await testSubjects.existOrFail('spacesNavSelector'); + }); + + it(`displays the manage button in the space selection menu`, async () => { + await svlCommonNavigation.navigateToKibanaHome(); + await svlCommonPage.assertProjectHeaderExists(); + await testSubjects.click('spacesNavSelector'); + await testSubjects.existOrFail('manageSpaces'); + }); + }); + }); + + describe('management', function () { + describe('as Viewer', function () { + before(async () => { + await svlCommonPage.loginAsViewer(); + }); + + it('does not display the space management card', async () => { + await svlCommon.navigateToApp('management'); + await testSubjects.missingOrFail('app-card-spaces'); + }); + }); + + describe('as Admin', function () { + before(async () => { + await svlCommonPage.loginAsAdmin(); + }); + + it('displays the space management card', async () => { + await svlCommon.navigateToApp('management'); + await testSubjects.existOrFail('app-card-spaces'); + }); + + // xpack.spaces.allowFeatureVisibility: false for all solutions + it(`does not display feature visibility`, async () => { + await svlCommon.navigateToApp('management'); + await testSubjects.click('app-card-spaces'); + + // create + await testSubjects.click('createSpace'); + await testSubjects.missingOrFail('hideAllFeaturesLink'); + await testSubjects.click('cancel-space-button'); + + // edit + await testSubjects.click('default-hyperlink'); + await testSubjects.missingOrFail('hideAllFeaturesLink'); + }); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/spaces/spaces_selection_enabled.ts b/x-pack/test_serverless/functional/test_suites/common/spaces/spaces_selection_enabled.ts deleted file mode 100644 index e998b25d24a11..0000000000000 --- a/x-pack/test_serverless/functional/test_suites/common/spaces/spaces_selection_enabled.ts +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -// Note: this suite is currently only called from the feature flags test config: -// x-pack/test_serverless/functional/test_suites/search/config.feature_flags.ts -// This file can take the place of the spaces_selection test file when spaces -// are enabled permanently in serverless. - -import { FtrProviderContext } from '../../../ftr_provider_context'; - -export default function ({ getPageObject, getService }: FtrProviderContext) { - const svlCommonPage = getPageObject('svlCommonPage'); - const svlCommonNavigation = getService('svlCommonNavigation'); - const testSubjects = getService('testSubjects'); - - describe('space selection', function () { - describe('as Viewer', function () { - before(async () => { - await svlCommonPage.loginAsViewer(); - }); - - it('displays the space selection menu in header', async () => { - await svlCommonNavigation.navigateToKibanaHome(); - await svlCommonPage.assertProjectHeaderExists(); - - await testSubjects.existOrFail('spacesNavSelector'); - }); - - it(`does not display the manage button in the space selection menu`, async () => { - await svlCommonNavigation.navigateToKibanaHome(); - await svlCommonPage.assertProjectHeaderExists(); - await testSubjects.click('spacesNavSelector'); - await testSubjects.missingOrFail('manageSpaces'); - }); - }); - - describe('as Admin', function () { - before(async () => { - await svlCommonPage.loginAsAdmin(); - }); - - it('displays the space selection menu in header', async () => { - await svlCommonNavigation.navigateToKibanaHome(); - await svlCommonPage.assertProjectHeaderExists(); - await testSubjects.existOrFail('spacesNavSelector'); - }); - - it(`displays the manage button in the space selection menu`, async () => { - await svlCommonNavigation.navigateToKibanaHome(); - await svlCommonPage.assertProjectHeaderExists(); - await testSubjects.click('spacesNavSelector'); - await testSubjects.existOrFail('manageSpaces'); - }); - }); - }); -} diff --git a/x-pack/test_serverless/functional/test_suites/observability/config.feature_flags.ts b/x-pack/test_serverless/functional/test_suites/observability/config.feature_flags.ts index f28a8bdb40377..8d85455f4588a 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/config.feature_flags.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/config.feature_flags.ts @@ -22,6 +22,7 @@ export default createTestConfig({ '--xpack.infra.enabled=true', '--xpack.infra.featureFlags.customThresholdAlertsEnabled=true', '--xpack.security.roleManagementEnabled=true', + `--xpack.cloud.serverless.project_id='fakeprojectid'`, `--xpack.cloud.base_url='https://cloud.elastic.co'`, `--xpack.cloud.organization_url='/account/members'`, `--xpack.spaces.maxSpaces=100`, // enables spaces UI capabilities diff --git a/x-pack/test_serverless/functional/test_suites/observability/index.feature_flags.ts b/x-pack/test_serverless/functional/test_suites/observability/index.feature_flags.ts index 24a7c41caeaee..955d839a38d26 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/index.feature_flags.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/index.feature_flags.ts @@ -13,6 +13,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./infra')); loadTestFile(require.resolve('../common/platform_security/navigation/management_nav_cards.ts')); loadTestFile(require.resolve('../common/platform_security/roles.ts')); - loadTestFile(require.resolve('../common/spaces/spaces_selection_enabled.ts')); + loadTestFile(require.resolve('../common/spaces/multiple_spaces_enabled.ts')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/search/index.feature_flags.ts b/x-pack/test_serverless/functional/test_suites/search/index.feature_flags.ts index 44cd17a0c9fd3..03dc3b8b6ead8 100644 --- a/x-pack/test_serverless/functional/test_suites/search/index.feature_flags.ts +++ b/x-pack/test_serverless/functional/test_suites/search/index.feature_flags.ts @@ -13,6 +13,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./elasticsearch_start.ts')); loadTestFile(require.resolve('../common/platform_security/navigation/management_nav_cards.ts')); loadTestFile(require.resolve('../common/platform_security/roles.ts')); - loadTestFile(require.resolve('../common/spaces/spaces_selection_enabled.ts')); + loadTestFile(require.resolve('../common/spaces/multiple_spaces_enabled.ts')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/security/index.feature_flags.ts b/x-pack/test_serverless/functional/test_suites/security/index.feature_flags.ts index a260942f1a4fc..212632be442d3 100644 --- a/x-pack/test_serverless/functional/test_suites/security/index.feature_flags.ts +++ b/x-pack/test_serverless/functional/test_suites/security/index.feature_flags.ts @@ -12,6 +12,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { // add tests that require feature flags, defined in config.feature_flags.ts loadTestFile(require.resolve('../common/platform_security/navigation/management_nav_cards.ts')); loadTestFile(require.resolve('../common/platform_security/roles.ts')); - loadTestFile(require.resolve('../common/spaces/spaces_selection_enabled.ts')); + loadTestFile(require.resolve('../common/spaces/multiple_spaces_enabled.ts')); }); } diff --git a/x-pack/test_serverless/shared/services/index.ts b/x-pack/test_serverless/shared/services/index.ts index 631d047d8fcfb..2252d024e32e7 100644 --- a/x-pack/test_serverless/shared/services/index.ts +++ b/x-pack/test_serverless/shared/services/index.ts @@ -6,10 +6,12 @@ */ import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; +import { services as deploymentAgnosticServices } from '@kbn/test-suites-xpack/api_integration/deployment_agnostic/services'; import { SupertestProvider } from './supertest'; import { SvlCommonApiServiceProvider } from './svl_common_api'; import { SvlReportingServiceProvider } from './svl_reporting'; import { DataViewApiProvider } from './data_view_api'; +import { PlatformSecurityUtilsProvider } from './platform_security_utils'; export type { InternalRequestHeader, @@ -25,5 +27,8 @@ export const services = { svlCommonApi: SvlCommonApiServiceProvider, svlReportingApi: SvlReportingServiceProvider, svlUserManager: commonFunctionalServices.samlAuth, + samlAuth: commonFunctionalServices.samlAuth, // <--temp workaround until we can unify naming + roleScopedSupertest: deploymentAgnosticServices.roleScopedSupertest, dataViewApi: DataViewApiProvider, + platformSecurityUtils: PlatformSecurityUtilsProvider, }; diff --git a/x-pack/test_serverless/shared/services/platform_security_utils.ts b/x-pack/test_serverless/shared/services/platform_security_utils.ts new file mode 100644 index 0000000000000..eb7b673637899 --- /dev/null +++ b/x-pack/test_serverless/shared/services/platform_security_utils.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 { FtrProviderContext } from '../../functional/ftr_provider_context'; + +export function PlatformSecurityUtilsProvider({ getService }: FtrProviderContext) { + const es = getService('es'); + const log = getService('log'); + + return { + // call it from 'samlAuth' service when tests are migrated to deployment-agnostic + async clearAllRoles() { + const existingRoles = await es.security.getRole(); + const esRolesNames = Object.entries(existingRoles) + .filter(([roleName, esRole]) => { + return !esRole.metadata?._reserved; + }) + .map(([roleName]) => roleName); + + if (esRolesNames.length > 0) { + await Promise.all( + esRolesNames.map(async (roleName) => { + await es.security.deleteRole({ name: roleName }); + }) + ); + } else { + log.debug('No Roles to delete.'); + } + }, + }; +} diff --git a/x-pack/test_serverless/tsconfig.json b/x-pack/test_serverless/tsconfig.json index 1770916bbace2..c27f5ea4fdda2 100644 --- a/x-pack/test_serverless/tsconfig.json +++ b/x-pack/test_serverless/tsconfig.json @@ -98,6 +98,7 @@ "@kbn/test-suites-src", "@kbn/console-plugin", "@kbn/cloud-security-posture-common", + "@kbn/security-plugin-types-common", "@kbn/core-saved-objects-import-export-server-internal", ] } From 7ad92ba86fce8f56955d010a9dc62c3d4eec8de7 Mon Sep 17 00:00:00 2001 From: Carlos Crespo Date: Fri, 6 Sep 2024 13:08:03 +0200 Subject: [PATCH 79/99] [Infra] Attempt to fix flaky test (#192091) fixes [#191806](https://github.com/elastic/kibana/issues/191806) ## Summary It was a weird problem that could only be reproduced by running the host_view test after the node_details test. The cause was that the synthtrace data was not fully cleaned in between tests --- .../lib/infra/infra_synthtrace_es_client.ts | 2 - .../test/functional/apps/infra/home_page.ts | 14 ++--- .../test/functional/apps/infra/hosts_view.ts | 59 +++++++++++-------- x-pack/test/functional/apps/infra/index.ts | 3 +- .../infra/metrics_source_configuration.ts | 23 +++++--- .../functional/apps/infra/node_details.ts | 30 +++------- 6 files changed, 64 insertions(+), 67 deletions(-) diff --git a/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_es_client.ts b/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_es_client.ts index dcd5e6da2d261..7aac8cfb1aad4 100644 --- a/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_es_client.ts +++ b/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_es_client.ts @@ -27,8 +27,6 @@ export class InfraSynthtraceEsClient extends SynthtraceEsClient { 'metrics-kubernetes*', 'metrics-docker*', 'metrics-aws*', - 'metricbeat-*', - 'logs-*', ]; } } diff --git a/x-pack/test/functional/apps/infra/home_page.ts b/x-pack/test/functional/apps/infra/home_page.ts index 50e055f5bc6bf..339c71c42e5bf 100644 --- a/x-pack/test/functional/apps/infra/home_page.ts +++ b/x-pack/test/functional/apps/infra/home_page.ts @@ -74,11 +74,16 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('Home page', function () { this.tags('includeFirefox'); + let synthEsClient: InfraSynthtraceEsClient; before(async () => { + synthEsClient = await getInfraSynthtraceEsClient(esClient); await kibanaServer.savedObjects.cleanStandardList(); + return synthEsClient.clean(); }); + after(() => synthEsClient.clean()); + describe('without metrics present', () => { it('renders an empty data prompt and redirects to the onboarding page', async () => { await pageObjects.common.navigateToApp('infraOps'); @@ -110,10 +115,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); describe('with metrics present', () => { - let synthEsClient: InfraSynthtraceEsClient; before(async () => { - synthEsClient = await getInfraSynthtraceEsClient(esClient); - await synthEsClient.clean(); await synthEsClient.index([ generateHostData({ from: DATE_WITH_HOSTS_DATA_FROM, @@ -134,10 +136,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.common.navigateToApp('infraOps'); await pageObjects.infraHome.waitForLoading(); }); - after(async () => { - await browser.removeLocalStorageItem(KUBERNETES_TOUR_STORAGE_KEY); - await synthEsClient.clean(); - }); + + after(async () => browser.removeLocalStorageItem(KUBERNETES_TOUR_STORAGE_KEY)); it('renders the correct page title', async () => { await pageObjects.header.waitUntilLoadingHasFinished(); diff --git a/x-pack/test/functional/apps/infra/hosts_view.ts b/x-pack/test/functional/apps/infra/hosts_view.ts index 5f2dd01bb980e..90c2b2fdfc9c1 100644 --- a/x-pack/test/functional/apps/infra/hosts_view.ts +++ b/x-pack/test/functional/apps/infra/hosts_view.ts @@ -298,15 +298,38 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { (await pageObjects.infraHostsView.isKPIChartsLoaded()) ); - // Failing: See https://github.com/elastic/kibana/issues/191806 - describe.skip('Hosts View', function () { + describe('Hosts View', function () { let synthEsInfraClient: InfraSynthtraceEsClient; let syntEsLogsClient: LogsSynthtraceEsClient; + let synthtraceApmClient: ApmSynthtraceEsClient; + + before(async () => { + synthEsInfraClient = await getInfraSynthtraceEsClient(esClient); + syntEsLogsClient = await getLogsSynthtraceEsClient(esClient); + const version = (await apmSynthtraceKibanaClient.installApmPackage()).version; + synthtraceApmClient = await getApmSynthtraceEsClient({ + client: esClient, + packageVersion: version, + }); + + return Promise.all([ + synthtraceApmClient.clean(), + synthEsInfraClient.clean(), + syntEsLogsClient.clean(), + ]); + }); + + after(async () => { + return Promise.all([ + apmSynthtraceKibanaClient.uninstallApmPackage(), + synthtraceApmClient.clean(), + synthEsInfraClient.clean(), + syntEsLogsClient.clean(), + ]); + }); describe('#Onboarding', function () { before(async () => { - synthEsInfraClient = await getInfraSynthtraceEsClient(esClient); - await synthEsInfraClient.clean(); await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH); }); @@ -325,14 +348,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); describe('#With data', function () { - let synthtraceApmClient: ApmSynthtraceEsClient; before(async () => { - synthEsInfraClient = await getInfraSynthtraceEsClient(esClient); - syntEsLogsClient = await getLogsSynthtraceEsClient(esClient); - const version = (await apmSynthtraceKibanaClient.installApmPackage()).version; - synthtraceApmClient = await getApmSynthtraceEsClient({ - client: esClient, - packageVersion: version, + const hosts = generateHostData({ + from: DATE_WITH_HOSTS_DATA_FROM, + to: DATE_WITH_HOSTS_DATA_TO, + hosts: SYNTH_HOSTS, }); const services = generateAddServicesToExistingHost({ @@ -350,26 +370,15 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await browser.setWindowSize(1600, 1200); - return Promise.all([ + await Promise.all([ + synthEsInfraClient.index(hosts), synthtraceApmClient.index(services), - synthEsInfraClient.index( - generateHostData({ - from: DATE_WITH_HOSTS_DATA_FROM, - to: DATE_WITH_HOSTS_DATA_TO, - hosts: SYNTH_HOSTS, - }) - ), syntEsLogsClient.index(logs), ]); }); after(async () => { - return Promise.all([ - apmSynthtraceKibanaClient.uninstallApmPackage(), - synthtraceApmClient.clean(), - synthEsInfraClient.clean(), - browser.removeLocalStorageItem(HOSTS_LINK_LOCAL_STORAGE_KEY), - ]); + return browser.removeLocalStorageItem(HOSTS_LINK_LOCAL_STORAGE_KEY); }); describe('#Single Host Flyout', () => { diff --git a/x-pack/test/functional/apps/infra/index.ts b/x-pack/test/functional/apps/infra/index.ts index 5ad5c004c30c9..999d7342f4639 100644 --- a/x-pack/test/functional/apps/infra/index.ts +++ b/x-pack/test/functional/apps/infra/index.ts @@ -15,11 +15,12 @@ export default ({ loadTestFile }: FtrProviderContext) => { describe('Metrics UI', function () { loadTestFile(require.resolve('./home_page')); - loadTestFile(require.resolve('./metrics_source_configuration')); loadTestFile(require.resolve('./metrics_anomalies')); loadTestFile(require.resolve('./metrics_explorer')); loadTestFile(require.resolve('./node_details')); loadTestFile(require.resolve('./hosts_view')); + // keep this test last as it can potentially break other tests + loadTestFile(require.resolve('./metrics_source_configuration')); }); describe('Logs UI', function () { diff --git a/x-pack/test/functional/apps/infra/metrics_source_configuration.ts b/x-pack/test/functional/apps/infra/metrics_source_configuration.ts index 177e675785a41..46d20489e4d36 100644 --- a/x-pack/test/functional/apps/infra/metrics_source_configuration.ts +++ b/x-pack/test/functional/apps/infra/metrics_source_configuration.ts @@ -31,17 +31,22 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const kibanaServer = getService('kibanaServer'); describe('Infrastructure Source Configuration', function () { - before(async () => kibanaServer.savedObjects.cleanStandardList()); - after(async () => kibanaServer.savedObjects.cleanStandardList()); + before(async () => + Promise.all([ + esArchiver.load('x-pack/test/functional/es_archives/infra/alerts'), + esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'), + kibanaServer.savedObjects.cleanStandardList(), + ]) + ); + after(async () => + Promise.all([ + esArchiver.unload('x-pack/test/functional/es_archives/infra/alerts'), + esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'), + kibanaServer.savedObjects.cleanStandardList(), + ]) + ); describe('with metrics present', () => { - before(async () => - esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs') - ); - after(async () => - esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs') - ); - it('renders the waffle map', async () => { await pageObjects.common.navigateToApp('infraOps'); await pageObjects.infraHome.goToTime(DATE_WITH_DATA); diff --git a/x-pack/test/functional/apps/infra/node_details.ts b/x-pack/test/functional/apps/infra/node_details.ts index 4d31091caabb5..f88a5cfb736a9 100644 --- a/x-pack/test/functional/apps/infra/node_details.ts +++ b/x-pack/test/functional/apps/infra/node_details.ts @@ -139,19 +139,16 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { let synthEsClient: InfraSynthtraceEsClient; before(async () => { synthEsClient = await getInfraSynthtraceEsClient(esClient); - await synthEsClient.clean(); await kibanaServer.savedObjects.cleanStandardList(); await browser.setWindowSize(1600, 1200); - }); - after(async () => { - await synthEsClient.clean(); + return synthEsClient.clean(); }); + after(() => synthEsClient.clean()); + describe('#Asset Type: host', () => { before(async () => { - synthEsClient = await getInfraSynthtraceEsClient(esClient); - await synthEsClient.clean(); await synthEsClient.index( generateHostData({ from: DATE_WITH_HOSTS_DATA_FROM, @@ -159,20 +156,15 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { hosts: HOSTS, }) ); + await navigateToNodeDetails('host-1', 'host', { name: 'host-1', }); await pageObjects.header.waitUntilLoadingHasFinished(); - await pageObjects.timePicker.setAbsoluteRange( - START_HOST_DATE.format(DATE_PICKER_FORMAT), - END_HOST_DATE.format(DATE_PICKER_FORMAT) - ); }); - after(async () => { - await synthEsClient.clean(); - }); + after(() => synthEsClient.clean()); it('preserves selected tab between page reloads', async () => { await testSubjects.missingOrFail('infraAssetDetailsMetadataTable'); @@ -633,8 +625,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('#Asset type: host with kubernetes section', () => { before(async () => { - synthEsClient = await getInfraSynthtraceEsClient(esClient); - await synthEsClient.clean(); await synthEsClient.index( generateHostsWithK8sNodeData({ from: DATE_WITH_HOSTS_DATA_FROM, @@ -651,9 +641,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ); }); - after(async () => { - await synthEsClient.clean(); - }); + after(() => synthEsClient.clean()); describe('Overview Tab', () => { before(async () => { @@ -727,8 +715,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('#Asset Type: container', () => { before(async () => { - synthEsClient = await getInfraSynthtraceEsClient(esClient); - await synthEsClient.clean(); await synthEsClient.index( generateDockerContainersData({ from: DATE_WITH_DOCKER_DATA_FROM, @@ -744,9 +730,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ); }); - after(async () => { - await synthEsClient.clean(); - }); + after(() => synthEsClient.clean()); describe('when container asset view is disabled', () => { before(async () => { From 4041d274b35cff51fbb224b925fcc9a10563dba0 Mon Sep 17 00:00:00 2001 From: Gloria Hornero Date: Fri, 6 Sep 2024 13:09:18 +0200 Subject: [PATCH 80/99] [ON-WEEK][POC] Playwright (#190803) ## UPDATE It has been removed the execution of the playwright tests on buildkite, the execution will be re-enabled as soon as we are ready and as described below in the PR, there are still steps pending to be done. ## Motivation **Cypress is not performing well lately.** * We have been facing significant performance issues with Cypress. For instance, it takes a long time to open the visual interface and start executing tests. **Teams are finding it increasingly challenging to write new tests and debug existing ones.** * The time and effort required to create new tests or troubleshoot existing ones have become burdensome. **Concern about the impact this could have on our testing practices.** * Lose motivation to write tests or, worse, skip writing crucial tests. ## Why Playwright? * Compared to Cypress, Playwright seems to be known for its faster execution times and lower resource consumption. What could have a positive impact by having faster feedback during development and execution of new tests as well as more efficient use of CI resources. * Provides powerful debugging tools which can make easier to write, debug and execute tests. * Seems to provide the same capabilities we currently use in our Cypress tests. * Given Playwright's active development and backing by Microsoft, it is likely to continue evolving rapidly, making it a safe long-term choice. Considering all the above, Playwright seems to be a strong candidate to replace Cypress and address all the issues we are facing lately regarding UI test automation. ## Objective of this POC To write in Playwright a couple of tests we currently have on Cypress to check the performance of the tool as well as the development experience. The tests selected have been: - [enable_risk_score_redirect.cy.ts](https://github.com/elastic/kibana/blob/main/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/dashboards/enable_risk_score_redirect.cy.ts) - Owned by Entity Analytics team and selected by its simplicity since it does not need any special setup to be executed and is short. - [manual_rule_run.cy.ts](https://github.com/elastic/kibana/blob/main/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_gaps/manual_rule_run.cy.ts) - Owned by Detection Engine team and selected because is short and adds a bit more of complexity due to it needs of clean-up and setting up initial data through the API. ## How to execute the tests ### Visual mode - Navigate to: `x-pack/test/security_solution_playwright` - Execute: `yarn open:ess` for ESS environment or `yarn open:serverless` for serverless environment. ### Headless mode - Navigate to: `x-pack/test/security_solution_playwright` - Execute: `yarn run:ess` for ESS environment or `yarn run:serverless` for serverless environment. ### From VScode - Install `Playwright Test for VScode` extension by Microsoft - Navigate to: `x-pack/test/security_solution_playwright` - Execute: `yarn open:ess` for ESS environment or `yarn open:serverless` for serverless environment. - Open your IDE - Click on the `Testing` icon - On the `Test Explorer` click on the three dots to select the profile you are going to execute `ess` or `serverless` - Click on the test you want to execute or navigate to the spec file of the test and execute it from the same spec. ## My experience - Tests are way easier to implement than with Cypress. - Playwright does not rely on chainable commands. Chainable commands on Cypress can lead to confusing code. - Without chainable commands, the flow of the tests is more explicit and easier to understand. - You can notice that the tool has been designed with Typescript in mind. - Is super easy to implement the Page Object Model pattern (POM). - With POM the test code is clean and focused on "what" rather than "how". - Love the fact that you can execute the tests from the same IDE without having to switch windows during test development. - The visual mode execution gives you lots of information out of the box. ## The scope of this PR - Sets the initial infrastructure to write and execute tests with Playwright. - Has examples and set a basis about how to write tests using the POM. - Allows the execution of the tests in ESS and serverless (just stateless environment). - Integrates the execution of the tests with buildkite. ## Pending to be done/investigate - Proper readme - How to split tests and PO between the different teams - Good reports on CI - Upload screenshots on CI - Flaky test suite runner - Complete the labeling - Execution of the tests on MKI environments ## FAQ **Can I start adding tests to playwright?** Currently, you can explore and experiment with Playwright, but there is still work pending to be done to make the tool officially usable. **Why security engineering productivity is the owner of the playwright folder?** This is something temporary to make sure that good practices are followed. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: dkirchan Co-authored-by: Aleh Zasypkin Co-authored-by: Jon --- .../ftr_security_serverless_configs.yml | 3 + .buildkite/ftr_security_stateful_configs.yml | 3 + .../security_solution/playwright.yml | 30 + .../security_serverless_playwright.sh | 14 + .../security_solution_playwright.sh | 14 + .github/CODEOWNERS | 1 + .gitignore | 8 + kbn_pm/src/lib/bazel.mjs | 4 + package.json | 5 +- renovate.json | 9 + .../scripts/run_playwright/playwright.ts | 377 + .../run_playwright/start_playwright.js | 9 + .../default_configs/stateful.config.base.ts | 1 - x-pack/test/examples/config.ts | 1 - .../services/ml/stack_management_jobs.ts | 1 - .../apps/triggers_actions_ui/shared/config.ts | 1 - x-pack/test/licensing_plugin/config.public.ts | 1 - x-pack/test/load/runner.ts | 1 - x-pack/test/plugin_functional/config.ts | 1 - .../common/config.ts | 2 - x-pack/test/scalability/config.ts | 1 - .../test/security_solution_cypress/config.ts | 2 + .../cypress/tasks/api_calls/common.ts | 2 +- .../serverless_config.ts | 2 + .../api_utils/api_key.ts | 84 + .../api_utils/documents.ts | 30 + .../api_utils/headers.ts | 37 + .../api_utils/rules.ts | 50 + .../es_archives/auditbeat_single/data.json | 123 + .../auditbeat_single/mappings.json | 7854 +++++++++++++++++ .../fixtures/es_archiver.ts | 61 + .../fixtures/saml.ts | 41 + .../security_solution_playwright/index.d.ts | 13 + .../security_solution_playwright/package.json | 15 + .../entity_analytics_management_po.ts | 23 + .../page_objects/entity_analytics_po.ts | 51 + .../page_objects/page_factory.ts | 40 + .../page_objects/rule_details_page_po.ts | 44 + .../page_objects/rule_management_po.ts | 56 + .../playwright.config.ts | 59 + .../tests/enable_risk_score_redirect.spec.ts | 45 + .../tests/manual_rule_run.spec.ts | 58 + .../tests/setup/login_ess.ts | 30 + .../tests/setup/login_serverless.ts | 39 + .../tsconfig.json | 17 + .../spaces_api_integration/common/config.ts | 1 - yarn.lock | 30 +- 47 files changed, 9280 insertions(+), 14 deletions(-) create mode 100644 .buildkite/pipelines/pull_request/security_solution/playwright.yml create mode 100755 .buildkite/scripts/steps/functional/security_serverless_playwright.sh create mode 100755 .buildkite/scripts/steps/functional/security_solution_playwright.sh create mode 100644 x-pack/plugins/security_solution/scripts/run_playwright/playwright.ts create mode 100644 x-pack/plugins/security_solution/scripts/run_playwright/start_playwright.js create mode 100644 x-pack/test/security_solution_playwright/api_utils/api_key.ts create mode 100644 x-pack/test/security_solution_playwright/api_utils/documents.ts create mode 100644 x-pack/test/security_solution_playwright/api_utils/headers.ts create mode 100644 x-pack/test/security_solution_playwright/api_utils/rules.ts create mode 100644 x-pack/test/security_solution_playwright/es_archives/auditbeat_single/data.json create mode 100644 x-pack/test/security_solution_playwright/es_archives/auditbeat_single/mappings.json create mode 100644 x-pack/test/security_solution_playwright/fixtures/es_archiver.ts create mode 100644 x-pack/test/security_solution_playwright/fixtures/saml.ts create mode 100644 x-pack/test/security_solution_playwright/index.d.ts create mode 100644 x-pack/test/security_solution_playwright/package.json create mode 100644 x-pack/test/security_solution_playwright/page_objects/entity_analytics_management_po.ts create mode 100644 x-pack/test/security_solution_playwright/page_objects/entity_analytics_po.ts create mode 100644 x-pack/test/security_solution_playwright/page_objects/page_factory.ts create mode 100644 x-pack/test/security_solution_playwright/page_objects/rule_details_page_po.ts create mode 100644 x-pack/test/security_solution_playwright/page_objects/rule_management_po.ts create mode 100644 x-pack/test/security_solution_playwright/playwright.config.ts create mode 100644 x-pack/test/security_solution_playwright/tests/enable_risk_score_redirect.spec.ts create mode 100644 x-pack/test/security_solution_playwright/tests/manual_rule_run.spec.ts create mode 100644 x-pack/test/security_solution_playwright/tests/setup/login_ess.ts create mode 100644 x-pack/test/security_solution_playwright/tests/setup/login_serverless.ts create mode 100644 x-pack/test/security_solution_playwright/tsconfig.json diff --git a/.buildkite/ftr_security_serverless_configs.yml b/.buildkite/ftr_security_serverless_configs.yml index 3bc5208c4a784..a6aca2fe7750e 100644 --- a/.buildkite/ftr_security_serverless_configs.yml +++ b/.buildkite/ftr_security_serverless_configs.yml @@ -12,6 +12,9 @@ disabled: - x-pack/test_serverless/functional/test_suites/security/cypress/security_config.ts - x-pack/test/security_solution_cypress/serverless_config.ts + # Playwright + - x-pack/test/security_solution_playwright/serverless_config.ts + # Serverless base config files - x-pack/test_serverless/api_integration/config.base.ts - x-pack/test_serverless/functional/config.base.ts diff --git a/.buildkite/ftr_security_stateful_configs.yml b/.buildkite/ftr_security_stateful_configs.yml index a72f5287d189b..7238b96225519 100644 --- a/.buildkite/ftr_security_stateful_configs.yml +++ b/.buildkite/ftr_security_stateful_configs.yml @@ -24,6 +24,9 @@ disabled: - x-pack/test/threat_intelligence_cypress/cli_config_parallel.ts - x-pack/test/threat_intelligence_cypress/config.ts + # Playwright + - x-pack/test/security_solution_playwright/playwright.config.ts + defaultQueue: 'n2-4-spot' enabled: - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/actions/trial_license_complete_tier/configs/ess.config.ts diff --git a/.buildkite/pipelines/pull_request/security_solution/playwright.yml b/.buildkite/pipelines/pull_request/security_solution/playwright.yml new file mode 100644 index 0000000000000..694a7ed588089 --- /dev/null +++ b/.buildkite/pipelines/pull_request/security_solution/playwright.yml @@ -0,0 +1,30 @@ +steps: + - command: .buildkite/scripts/steps/functional/security_serverless_playwright.sh + label: 'Serverless Playwright - Security Solution Tests' + agents: + machineType: n2-standard-4 + preemptible: true + depends_on: + - build + - quick_checks + timeout_in_minutes: 60 + parallelism: 1 + retry: + automatic: + - exit_status: '-1' + limit: 1 + + - command: .buildkite/scripts/steps/functional/security_solution_playwright.sh + label: 'Playwright - Security Solution Tests' + agents: + machineType: n2-standard-4 + preemptible: true + depends_on: + - build + - quick_checks + timeout_in_minutes: 60 + parallelism: 1 + retry: + automatic: + - exit_status: '-1' + limit: 1 diff --git a/.buildkite/scripts/steps/functional/security_serverless_playwright.sh b/.buildkite/scripts/steps/functional/security_serverless_playwright.sh new file mode 100755 index 0000000000000..3b68702eb3467 --- /dev/null +++ b/.buildkite/scripts/steps/functional/security_serverless_playwright.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source .buildkite/scripts/steps/functional/common.sh + +export JOB=kibana-security-solution-playwright +export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION} + +echo "--- SERVERLESS - Security Solution Playwright Tests" + +cd x-pack/test/security_solution_playwright + +yarn run:serverless; exit_code=$?; exit $exit_code diff --git a/.buildkite/scripts/steps/functional/security_solution_playwright.sh b/.buildkite/scripts/steps/functional/security_solution_playwright.sh new file mode 100755 index 0000000000000..30729cfef6afe --- /dev/null +++ b/.buildkite/scripts/steps/functional/security_solution_playwright.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source .buildkite/scripts/steps/functional/common.sh + +export JOB=kibana-security-solution-playwright +export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION} + +echo "--- ESS - Security Solution Playwright Tests" + +cd x-pack/test/security_solution_playwright + +yarn run:ess; exit_code=$?; exit $exit_code \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 431a668ebe14c..5c10707e9328d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1481,6 +1481,7 @@ x-pack/test/security_solution_api_integration/test_suites/sources @elastic/secur /x-pack/test/security_solution_cypress/cypress/* @elastic/security-engineering-productivity /x-pack/test/security_solution_cypress/cypress/tasks/login.ts @elastic/security-engineering-productivity /x-pack/test/security_solution_cypress/es_archives @elastic/security-engineering-productivity +/x-pack/test/security_solution_playwright @elastic/security-engineering-productivity /x-pack/plugins/security_solution/scripts/run_cypress @MadameSheema @patrykkopycinski @maximpn @banderror ## Security Solution sub teams - Threat Hunting Investigations diff --git a/.gitignore b/.gitignore index baa0b5d34aeed..7e06f1e23f863 100644 --- a/.gitignore +++ b/.gitignore @@ -150,3 +150,11 @@ oas_docs/output/kibana.serverless.tmp*.yaml oas_docs/output/kibana.tmp*.yaml oas_docs/output/kibana.new.yaml oas_docs/output/kibana.serverless.new.yaml + +# Security Solution Playwright +x-pack/test/security_solution_playwright/test-results/ +x-pack/test/security_solution_playwright/playwright-report/ +x-pack/test/security_solution_playwright/blob-report/ +x-pack/test/security_solution_playwright/playwright/.cache/ +x-pack/test/security_solution_playwright/.auth/ +x-pack/test/security_solution_playwright/.env \ No newline at end of file diff --git a/kbn_pm/src/lib/bazel.mjs b/kbn_pm/src/lib/bazel.mjs index 481a0fd66aa57..ca374979763b6 100644 --- a/kbn_pm/src/lib/bazel.mjs +++ b/kbn_pm/src/lib/bazel.mjs @@ -152,6 +152,10 @@ export async function installYarnDeps(log, opts = undefined) { }); log.success('yarn deps installed'); + + await run('yarn', ['playwright', 'install']); + + log.success('Playwright browsers installed'); } /** diff --git a/package.json b/package.json index 9f7cd9862953a..a4bdd399676ad 100644 --- a/package.json +++ b/package.json @@ -1072,6 +1072,7 @@ "deepmerge": "^4.2.2", "del": "^6.1.0", "diff": "^5.1.0", + "dotenv": "^16.4.5", "elastic-apm-node": "^4.7.3", "email-addresses": "^5.0.0", "eventsource-parser": "^1.1.1", @@ -1462,6 +1463,7 @@ "@mapbox/vector-tile": "1.3.1", "@octokit/rest": "^17.11.2", "@parcel/watcher": "^2.1.0", + "@playwright/test": "=1.46.0", "@redocly/cli": "^1.21.0", "@statoscope/webpack-plugin": "^5.28.2", "@storybook/addon-a11y": "^6.5.16", @@ -1761,7 +1763,8 @@ "pirates": "^4.0.1", "piscina": "^3.2.0", "pixelmatch": "^5.3.0", - "playwright": "=1.38.0", + "playwright": "=1.46.0", + "playwright-chromium": "=1.46.0", "pngjs": "^3.4.0", "postcss": "^8.4.31", "postcss-loader": "^4.2.0", diff --git a/renovate.json b/renovate.json index 774dce52e3515..a7f84bf4e595f 100644 --- a/renovate.json +++ b/renovate.json @@ -485,6 +485,15 @@ "matchBaseBranches": ["main"], "labels": ["release_note:skip", "team:obs-entities"], "enabled": true + }, + { + "groupName": "Security Engineering Productivity", + "matchDepNames": ["dotenv", "playwright-chromium", "@playwright/test"], + "reviewers": ["team:security-engineering-productivity"], + "matchBaseBranches": ["main"], + "labels": ["Team: Sec Eng Productivity", "release_note:skip", "backport:all-open"], + "minimumReleaseAge": "7 days", + "enabled": true } ], "customManagers": [ diff --git a/x-pack/plugins/security_solution/scripts/run_playwright/playwright.ts b/x-pack/plugins/security_solution/scripts/run_playwright/playwright.ts new file mode 100644 index 0000000000000..3b51cf7c67a49 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/run_playwright/playwright.ts @@ -0,0 +1,377 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { run } from '@kbn/dev-cli-runner'; +import yargs from 'yargs'; +import _ from 'lodash'; +import globby from 'globby'; +import pMap from 'p-map'; +import { withProcRunner } from '@kbn/dev-proc-runner'; +import path from 'path'; +import fs from 'fs'; + +import { EsVersion, FunctionalTestRunner, runElasticsearch, runKibanaServer } from '@kbn/test'; + +import { + Lifecycle, + ProviderCollection, + readProviderSpec, +} from '@kbn/test/src/functional_test_runner/lib'; +import pRetry from 'p-retry'; +import execa from 'execa'; +import { prefixedOutputLogger } from '../endpoint/common/utils'; +import { createToolingLogger } from '../../common/endpoint/data_loaders/utils'; +import { parseTestFileConfig, retrieveIntegrations } from '../run_cypress/utils'; +import { getFTRConfig } from '../run_cypress/get_ftr_config'; +import type { StartedFleetServer } from '../endpoint/common/fleet_server/fleet_server_services'; +import { startFleetServer } from '../endpoint/common/fleet_server/fleet_server_services'; +import { createKbnClient } from '../endpoint/common/stack_services'; + +export const cli = () => { + run( + async ({ log: _cliLogger }) => { + const { argv } = yargs(process.argv.slice(2)) + .coerce('configFile', (arg) => (_.isArray(arg) ? _.last(arg) : arg)) + .coerce('spec', (arg) => (_.isArray(arg) ? _.last(arg) : arg)) + .coerce('env', (arg: string) => + arg.split(',').reduce((acc, curr) => { + const [key, value] = curr.split('='); + if (key === 'burn') { + acc[key] = parseInt(value, 10); + } else { + acc[key] = value; + } + return acc; + }, {} as Record) + ) + .boolean('inspect'); + + _cliLogger.info(` +---------------------------------------------- +Script arguments: +---------------------------------------------- +${JSON.stringify(argv, null, 2)} +---------------------------------------------- +`); + + const isOpen = argv._.includes('open'); + const playwrightConfigFilePath = require.resolve(`../../${argv.configFile}`) as string; + const playwrightConfigFile = await import(playwrightConfigFilePath); + + const log = prefixedOutputLogger('playwright', createToolingLogger()); + + log.info(` +---------------------------------------------- +Playwright config for file: ${playwrightConfigFilePath}: +---------------------------------------------- +${JSON.stringify(playwrightConfigFile, null, 2)} +---------------------------------------------- + + +`); + + const specConfig = playwrightConfigFile.testMatch; + const specArg = argv.spec; + const specPattern = specArg ?? specConfig; + const files = retrieveIntegrations(globby.sync(specPattern)); + const esPorts: number[] = [9200, 9220]; + const kibanaPorts: number[] = [5601, 5620]; + const fleetServerPorts: number[] = [8220]; + + const getEsPort = (): T | number => { + if (isOpen) { + return 9220; + } + + const esPort = parseInt(`92${Math.floor(Math.random() * 89) + 10}`, 10); + if (esPorts.includes(esPort)) { + return getEsPort(); + } + esPorts.push(esPort); + return esPort; + }; + + const getKibanaPort = (): T | number => { + if (isOpen) { + return 5620; + } + + const kibanaPort = parseInt(`56${Math.floor(Math.random() * 89) + 10}`, 10); + if (kibanaPorts.includes(kibanaPort)) { + return getKibanaPort(); + } + kibanaPorts.push(kibanaPort); + return kibanaPort; + }; + + const getFleetServerPort = (): T | number => { + if (isOpen) { + return 8220; + } + + const fleetServerPort = parseInt(`82${Math.floor(Math.random() * 89) + 10}`, 10); + if (fleetServerPorts.includes(fleetServerPort)) { + return getFleetServerPort(); + } + fleetServerPorts.push(fleetServerPort); + return fleetServerPort; + }; + + const cleanupServerPorts = ({ + esPort, + kibanaPort, + fleetServerPort, + }: { + esPort: number; + kibanaPort: number; + fleetServerPort: number; + }) => { + _.pull(esPorts, esPort); + _.pull(kibanaPorts, kibanaPort); + _.pull(fleetServerPorts, fleetServerPort); + }; + + const failedSpecFilePaths: string[] = []; + + const runSpecs = async (filePaths: string[]) => + pMap( + filePaths, + async (filePath) => { + let result: Error | undefined; + await withProcRunner(log, async (procs) => { + const abortCtrl = new AbortController(); + + const onEarlyExit = (msg: string) => { + log.error(msg); + abortCtrl.abort(); + }; + + const esPort: number = getEsPort(); + const kibanaPort: number = getKibanaPort(); + const fleetServerPort: number = getFleetServerPort(); + + const specFileFTRConfig = parseTestFileConfig(filePath); + const ftrConfigFilePath = path.resolve( + _.isArray(argv.ftrConfigFile) ? _.last(argv.ftrConfigFile) : argv.ftrConfigFile + ); + + const config = await getFTRConfig({ + log, + esPort, + kibanaPort, + fleetServerPort, + ftrConfigFilePath, + specFilePath: filePath, + specFileFTRConfig, + isOpen, + }); + + const createUrlFromFtrConfig = ( + type: 'elasticsearch' | 'kibana' | 'fleetserver', + withAuth: boolean = false + ): string => { + const getKeyPath = (keyPath: string = ''): string => { + return `servers.${type}${keyPath ? `.${keyPath}` : ''}`; + }; + + if (!config.get(getKeyPath())) { + throw new Error(`Unable to create URL for ${type}. Not found in FTR config at `); + } + + const url = new URL('http://localhost'); + + url.port = config.get(getKeyPath('port')); + url.protocol = config.get(getKeyPath('protocol')); + url.hostname = config.get(getKeyPath('hostname')); + + if (withAuth) { + url.username = config.get(getKeyPath('username')); + url.password = config.get(getKeyPath('password')); + } + + return url.toString().replace(/\/$/, ''); + }; + + const baseUrl = createUrlFromFtrConfig('kibana'); + const lifecycle = new Lifecycle(log); + + const providers = new ProviderCollection(log, [ + ...readProviderSpec('Service', { + lifecycle: () => lifecycle, + log: () => log, + config: () => config, + }), + ...readProviderSpec('Service', config.get('services')), + ]); + + const options = { + installDir: process.env.KIBANA_INSTALL_DIR, + ci: process.env.CI, + }; + let fleetServer: StartedFleetServer | undefined; + let shutdownEs; + + try { + shutdownEs = await pRetry( + async () => + runElasticsearch({ + config, + log, + name: `ftr-${esPort}`, + esFrom: config.get('esTestCluster')?.from || 'snapshot', + onEarlyExit, + }), + { retries: 2, forever: false } + ); + await runKibanaServer({ + procs, + config, + installDir: options?.installDir, + extraKbnOpts: + options?.installDir || options?.ci || !isOpen + ? [] + : ['--dev', '--no-dev-credentials'], + onEarlyExit, + inspect: argv.inspect, + }); + + if (playwrightConfigFile.env?.WITH_FLEET_SERVER) { + log.info(`Setting up fleet-server for this Cypress config`); + + const kbnClient = createKbnClient({ + url: baseUrl, + username: config.get('servers.kibana.username'), + password: config.get('servers.kibana.password'), + log, + }); + + fleetServer = await pRetry( + async () => + startFleetServer({ + kbnClient, + logger: log, + port: + fleetServerPort ?? config.has('servers.fleetserver.port') + ? (config.get('servers.fleetserver.port') as number) + : undefined, + // `force` is needed to ensure that any currently running fleet server (perhaps left + // over from an interrupted run) is killed and a new one restarted + force: true, + }), + { retries: 2, forever: false } + ); + } + + await providers.loadAll(); + const functionalTestRunner = new FunctionalTestRunner( + log, + config, + EsVersion.getDefault() + ); + const ftrEnv = await pRetry(() => functionalTestRunner.run(abortCtrl.signal), { + retries: 1, + }); + + // Normalized the set of available env vars in Playwright + const playwrightCustomEnv = { + ...ftrEnv, + // NOTE: + // ELASTICSEARCH_URL needs to be created here with auth because SIEM Playwright setup depends on it. At some + // points we should probably try to refactor that code to use `ELASTICSEARCH_URL_WITH_AUTH` instead + ELASTICSEARCH_URL: + ftrEnv.ELASTICSEARCH_URL ?? createUrlFromFtrConfig('elasticsearch', true), + ELASTICSEARCH_URL_WITH_AUTH: createUrlFromFtrConfig('elasticsearch', true), + ELASTICSEARCH_USERNAME: + ftrEnv.ELASTICSEARCH_USERNAME ?? config.get('servers.elasticsearch.username'), + ELASTICSEARCH_PASSWORD: + ftrEnv.ELASTICSEARCH_PASSWORD ?? config.get('servers.elasticsearch.password'), + FLEET_SERVER_URL: createUrlFromFtrConfig('fleetserver'), + KIBANA_URL: baseUrl, + KIBANA_URL_WITH_AUTH: createUrlFromFtrConfig('kibana', true), + KIBANA_USERNAME: config.get('servers.kibana.username'), + KIBANA_PASSWORD: config.get('servers.kibana.password'), + IS_SERVERLESS: config.get('serverless'), + }; + + const envFilePath = path.resolve( + __dirname, + '..', + '..', + '..', + '..', + 'test', + 'security_solution_playwright', + '.env' + ); + + const envContent = Object.entries(playwrightCustomEnv) + .map(([key, value]) => `${key}=${value}`) + .join('\n'); + + fs.writeFileSync(envFilePath, envContent); + + log.info(` + ---------------------------------------------- + Playwright run ENV for file: ${filePath} + ---------------------------------------------- + `); + + const project = playwrightCustomEnv.IS_SERVERLESS ? 'serverless' : 'ess'; + + if (isOpen) { + await execa.command( + `../../../node_modules/.bin/playwright test --config ${playwrightConfigFilePath} --ui --project ${project}`, + { + env: { + ...playwrightCustomEnv, + }, + stdout: process.stdout, + } + ); + } else { + await execa.command( + `../../../node_modules/.bin/playwright test --config ${playwrightConfigFilePath} --project ${project} --grep @${project}`, + { + env: { + ...playwrightCustomEnv, + FILE_PATH: filePath, + }, + stdout: process.stdout, + } + ); + } + } catch (error) { + log.error(error); + result = error; + failedSpecFilePaths.push(filePath); + } + + if (fleetServer) { + await fleetServer.stop(); + } + + await procs.stop('kibana'); + await shutdownEs?.(); + cleanupServerPorts({ esPort, kibanaPort, fleetServerPort }); + return result; + }); + return result; + }, + { + concurrency: 1, + } + ); + + await runSpecs(files); + }, + { + flags: { + allowUnexpected: true, + }, + } + ); +}; diff --git a/x-pack/plugins/security_solution/scripts/run_playwright/start_playwright.js b/x-pack/plugins/security_solution/scripts/run_playwright/start_playwright.js new file mode 100644 index 0000000000000..e69f8aa37a89d --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/run_playwright/start_playwright.js @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +require('../../../../../src/setup_node_env'); +require('./playwright').cli(); diff --git a/x-pack/test/api_integration/deployment_agnostic/default_configs/stateful.config.base.ts b/x-pack/test/api_integration/deployment_agnostic/default_configs/stateful.config.base.ts index 2fd2d61e1cf81..964627effe28b 100644 --- a/x-pack/test/api_integration/deployment_agnostic/default_configs/stateful.config.base.ts +++ b/x-pack/test/api_integration/deployment_agnostic/default_configs/stateful.config.base.ts @@ -19,7 +19,6 @@ import { FtrConfigProviderContext, } from '@kbn/test'; import path from 'path'; -// @ts-expect-error we have to check types with "allowJs: false" for now, causing this import to fail import { REPO_ROOT } from '@kbn/repo-info'; import { STATEFUL_ROLES_ROOT_PATH } from '@kbn/es'; import { DeploymentAgnosticCommonServices, services } from '../services'; diff --git a/x-pack/test/examples/config.ts b/x-pack/test/examples/config.ts index 01144389353b2..43fc26df42ab9 100644 --- a/x-pack/test/examples/config.ts +++ b/x-pack/test/examples/config.ts @@ -7,7 +7,6 @@ import { FtrConfigProviderContext, findTestPluginPaths } from '@kbn/test'; import { resolve } from 'path'; -// @ts-expect-error we have to check types with "allowJs: false" for now, causing this import to fail import { REPO_ROOT as KIBANA_ROOT } from '@kbn/repo-info'; export default async function ({ readConfigFile }: FtrConfigProviderContext) { 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 bbf985d4c0d67..ef40f8e7bc06d 100644 --- a/x-pack/test/functional/services/ml/stack_management_jobs.ts +++ b/x-pack/test/functional/services/ml/stack_management_jobs.ts @@ -6,7 +6,6 @@ */ import expect from '@kbn/expect'; -// @ts-expect-error we have to check types with "allowJs: false" for now, causing this import to fail import { REPO_ROOT } from '@kbn/repo-info'; import fs from 'fs'; import path from 'path'; diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/shared/config.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/shared/config.ts index eedd329f2b627..b72b4f600d3d8 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/shared/config.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/shared/config.ts @@ -7,7 +7,6 @@ import { FtrConfigProviderContext, findTestPluginPaths } from '@kbn/test'; import { resolve } from 'path'; -// @ts-expect-error we have to check types with "allowJs: false" for now, causing this import to fail import { REPO_ROOT as KIBANA_ROOT } from '@kbn/repo-info'; export default async function ({ readConfigFile }: FtrConfigProviderContext) { diff --git a/x-pack/test/licensing_plugin/config.public.ts b/x-pack/test/licensing_plugin/config.public.ts index efe6a950ffeb1..01ad77d8b3d80 100644 --- a/x-pack/test/licensing_plugin/config.public.ts +++ b/x-pack/test/licensing_plugin/config.public.ts @@ -6,7 +6,6 @@ */ import path from 'path'; -// @ts-expect-error we have to check types with "allowJs: false" for now, causing this import to fail import { REPO_ROOT as KIBANA_ROOT } from '@kbn/repo-info'; import { FtrConfigProviderContext } from '@kbn/test'; diff --git a/x-pack/test/load/runner.ts b/x-pack/test/load/runner.ts index 3a54c218d4ef0..7bb7189269040 100644 --- a/x-pack/test/load/runner.ts +++ b/x-pack/test/load/runner.ts @@ -7,7 +7,6 @@ import { withProcRunner } from '@kbn/dev-proc-runner'; import { resolve } from 'path'; -// @ts-expect-error we have to check types with "allowJs: false" for now, causing this import to fail import { REPO_ROOT } from '@kbn/repo-info'; import Fs from 'fs'; import { createFlagError } from '@kbn/dev-cli-errors'; diff --git a/x-pack/test/plugin_functional/config.ts b/x-pack/test/plugin_functional/config.ts index 825d3e7c1bad7..6d35ff68f8890 100644 --- a/x-pack/test/plugin_functional/config.ts +++ b/x-pack/test/plugin_functional/config.ts @@ -6,7 +6,6 @@ */ import { resolve } from 'path'; -// @ts-expect-error we have to check types with "allowJs: false" for now, causing this import to fail import { REPO_ROOT as KIBANA_ROOT } from '@kbn/repo-info'; import { FtrConfigProviderContext, findTestPluginPaths } from '@kbn/test'; import { services } from './services'; diff --git a/x-pack/test/saved_object_api_integration/common/config.ts b/x-pack/test/saved_object_api_integration/common/config.ts index 553762760b197..d6d450f4cdcbe 100644 --- a/x-pack/test/saved_object_api_integration/common/config.ts +++ b/x-pack/test/saved_object_api_integration/common/config.ts @@ -6,8 +6,6 @@ */ import path from 'path'; - -// @ts-expect-error we have to check types with "allowJs: false" for now, causing this import to fail import { REPO_ROOT } from '@kbn/repo-info'; import { FtrConfigProviderContext } from '@kbn/test'; diff --git a/x-pack/test/scalability/config.ts b/x-pack/test/scalability/config.ts index 3315276a688ca..cc47d4e2f2806 100644 --- a/x-pack/test/scalability/config.ts +++ b/x-pack/test/scalability/config.ts @@ -8,7 +8,6 @@ import { FtrConfigProviderContext, getKibanaCliLoggers } from '@kbn/test'; import fs from 'fs'; import path from 'path'; -// @ts-expect-error we have to check types with "allowJs: false" for now, causing this import to fail import { REPO_ROOT } from '@kbn/repo-info'; import { createFlagError } from '@kbn/dev-cli-errors'; import { v4 as uuidV4 } from 'uuid'; diff --git a/x-pack/test/security_solution_cypress/config.ts b/x-pack/test/security_solution_cypress/config.ts index 1bed88858601d..58d873369d99d 100644 --- a/x-pack/test/security_solution_cypress/config.ts +++ b/x-pack/test/security_solution_cypress/config.ts @@ -55,6 +55,8 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { // packages listed in fleet_packages.json // See: https://elastic.slack.com/archives/CNMNXV4RG/p1683033379063079 `--xpack.fleet.developer.bundledPackageLocation=./inexistentDir`, + '--csp.strict=false', + '--csp.warnLegacyBrowsers=false', ], }, }; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/common.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/common.ts index 7c78858070a20..80d7c2c106815 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/common.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/common.ts @@ -11,8 +11,8 @@ import { AllConnectorsResponse } from '@kbn/actions-plugin/common/routes/connect import { DETECTION_ENGINE_RULES_BULK_ACTION } from '@kbn/security-solution-plugin/common/constants'; import { ELASTICSEARCH_PASSWORD, ELASTICSEARCH_USERNAME } from '../../env_var_names_constants'; import { deleteAllDocuments } from './elasticsearch'; -import { DEFAULT_ALERTS_INDEX_PATTERN } from './alerts'; import { getSpaceUrl } from '../space'; +import { DEFAULT_ALERTS_INDEX_PATTERN } from './alerts'; export const API_AUTH = Object.freeze({ user: Cypress.env(ELASTICSEARCH_USERNAME), diff --git a/x-pack/test/security_solution_cypress/serverless_config.ts b/x-pack/test/security_solution_cypress/serverless_config.ts index c397eed4385f9..226f2db6dbbc0 100644 --- a/x-pack/test/security_solution_cypress/serverless_config.ts +++ b/x-pack/test/security_solution_cypress/serverless_config.ts @@ -35,6 +35,8 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { { product_line: 'cloud', product_tier: 'complete' }, ])}`, `--xpack.securitySolution.enableExperimental=${JSON.stringify(['manualRuleRunEnabled'])}`, + '--csp.strict=false', + '--csp.warnLegacyBrowsers=false', ], }, testRunner: SecuritySolutionConfigurableCypressTestRunner, diff --git a/x-pack/test/security_solution_playwright/api_utils/api_key.ts b/x-pack/test/security_solution_playwright/api_utils/api_key.ts new file mode 100644 index 0000000000000..e1f93c9937961 --- /dev/null +++ b/x-pack/test/security_solution_playwright/api_utils/api_key.ts @@ -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 axios from 'axios'; +import fs from 'fs'; +import yaml from 'js-yaml'; +import { ToolingLog } from '@kbn/tooling-log'; +import { HostOptions, SamlSessionManager } from '@kbn/test'; +import { resolve } from 'path'; +import { REPO_ROOT } from '@kbn/repo-info'; + +const getYamlData = (filePath: string): any => { + const fileContents = fs.readFileSync(filePath, 'utf8'); + return yaml.safeLoad(fileContents); +}; + +const getRoleConfiguration = (role: string, filePath: string): any => { + const data = getYamlData(filePath); + if (data[role]) { + return data[role]; + } else { + throw new Error(`Role '${role}' not found in the YAML file.`); + } +}; + +const rolesPath = + '../../../packages/kbn-es/src/serverless_resources/project_roles/security/roles.yml'; + +export const getApiKeyForUser = async () => { + const log = new ToolingLog({ level: 'verbose', writeTo: process.stdout }); + + const kbnHost = process.env.KIBANA_URL || process.env.BASE_URL; + const kbnUrl = new URL(kbnHost!); + + const hostOptions: HostOptions = { + protocol: kbnUrl.protocol as 'http' | 'https', + hostname: kbnUrl.hostname, + port: parseInt(kbnUrl.port, 10), + username: process.env.ELASTICSEARCH_USERNAME ?? '', + password: process.env.ELASTICSEARCH_PASSWORD ?? '', + }; + + const rolesFilename = process.env.PROXY_ORG ? `${process.env.PROXY_ORG}.json` : undefined; + const cloudUsersFilePath = resolve(REPO_ROOT, '.ftr', rolesFilename ?? 'role_users.json'); + + const samlSessionManager = new SamlSessionManager({ + hostOptions, + log, + isCloud: process.env.CLOUD_SERVERLESS === 'true', + cloudUsersFilePath, + }); + + const adminCookieHeader = await samlSessionManager.getApiCredentialsForRole('admin'); + + let roleDescriptor = {}; + + const roleConfig = getRoleConfiguration('admin', rolesPath); + + roleDescriptor = { ['system_indices_superuser']: roleConfig }; + + const response = await axios.post( + `${process.env.KIBANA_URL}/internal/security/api_key`, + { + name: 'myTestApiKey', + metadata: {}, + role_descriptors: roleDescriptor, + }, + { + headers: { + 'kbn-xsrf': 'cypress-creds', + 'x-elastic-internal-origin': 'security-solution', + ...adminCookieHeader, + }, + } + ); + + const apiKey = response.data.encoded; + + return apiKey; +}; diff --git a/x-pack/test/security_solution_playwright/api_utils/documents.ts b/x-pack/test/security_solution_playwright/api_utils/documents.ts new file mode 100644 index 0000000000000..b2432039e8a0b --- /dev/null +++ b/x-pack/test/security_solution_playwright/api_utils/documents.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 { APIRequestContext } from '@playwright/test'; +import { getCommonHeaders } from './headers'; + +export const deleteAllSecurityDocuments = async (request: APIRequestContext) => { + const securityIndexes = `.lists-*,.items-*,.alerts-security.alerts-*`; + const headers = await getCommonHeaders(); + + await request.post(`${process.env.ELASTICSEARCH_URL}/${securityIndexes}/_refresh`, { + headers, + }); + + await request.post( + `${process.env.ELASTICSEARCH_URL}/${securityIndexes}/_delete_by_query?conflicts=proceed&scroll_size=10000&refresh`, + { + headers, + data: { + query: { + match_all: {}, + }, + }, + } + ); +}; diff --git a/x-pack/test/security_solution_playwright/api_utils/headers.ts b/x-pack/test/security_solution_playwright/api_utils/headers.ts new file mode 100644 index 0000000000000..dfca3255dcc70 --- /dev/null +++ b/x-pack/test/security_solution_playwright/api_utils/headers.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 { INITIAL_REST_VERSION } from '@kbn/data-views-plugin/server/constants'; +import { getApiKeyForUser } from './api_key'; + +export const getCommonHeaders = async (additionalHeaders: Record = {}) => { + let auth = ''; + + if (process.env.IS_SERVERLESS === 'true') { + const apiKey = await getApiKeyForUser(); + auth = `ApiKey ${apiKey}`; + } else { + const username = process.env.ELASTICSEARCH_USERNAME || ''; + const password = process.env.ELASTICSEARCH_PASSWORD || ''; + const encodedCredentials = Buffer.from(`${username}:${password}`).toString('base64'); + + auth = `Basic ${encodedCredentials}`; + } + return { + 'kbn-xsrf': 'cypress-creds', + 'x-elastic-internal-origin': 'security-solution', + Authorization: auth, + ...additionalHeaders, + }; +}; + +export const getCommonHeadersWithApiVersion = async () => { + const header = await getCommonHeaders({ + 'elastic-api-version': INITIAL_REST_VERSION, + }); + return header; +}; diff --git a/x-pack/test/security_solution_playwright/api_utils/rules.ts b/x-pack/test/security_solution_playwright/api_utils/rules.ts new file mode 100644 index 0000000000000..0c6679472b22d --- /dev/null +++ b/x-pack/test/security_solution_playwright/api_utils/rules.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + DETECTION_ENGINE_RULES_BULK_ACTION, + DETECTION_ENGINE_RULES_URL, +} from '@kbn/security-solution-plugin/common/constants'; +import { APIRequestContext } from '@playwright/test'; +import { getRuleForAlertTesting } from '../../common/utils/security_solution'; +import { getCommonHeadersWithApiVersion } from './headers'; + +const indexes = [ + 'apm-*-transaction*', + 'auditbeat-*', + 'endgame-*', + 'filebeat-*', + 'logs-*', + 'packetbeat-*', + 'traces-apm*', + 'winlogbeat-*', + '-*elastic-cloud-logs-*', +]; + +export const createRule = async (request: APIRequestContext) => { + const data = getRuleForAlertTesting(indexes); + const headers = await getCommonHeadersWithApiVersion(); + const response = await request.post(DETECTION_ENGINE_RULES_URL, { + data, + headers, + }); + + return await response.json(); +}; + +export const deleteAllRules = async (request: APIRequestContext) => { + const headers = await getCommonHeadersWithApiVersion(); + const response = await request.post(DETECTION_ENGINE_RULES_BULK_ACTION, { + data: { + query: '', + action: 'delete', + }, + headers, + }); + + return await response.json(); +}; diff --git a/x-pack/test/security_solution_playwright/es_archives/auditbeat_single/data.json b/x-pack/test/security_solution_playwright/es_archives/auditbeat_single/data.json new file mode 100644 index 0000000000000..cb9a035e8d19d --- /dev/null +++ b/x-pack/test/security_solution_playwright/es_archives/auditbeat_single/data.json @@ -0,0 +1,123 @@ +{ + "type": "doc", + "value": { + "id": "_aZE5nwBOpWiDweSth_E", + "index": "auditbeat-2022", + "source": { + "@timestamp" : "2022-03-04T19:41:34.045Z", + "host" : { + "hostname" : "test.local", + "architecture" : "x86_64", + "os" : { + "platform" : "darwin", + "version" : "10.16", + "family" : "darwin", + "name" : "Mac OS X", + "kernel" : "21.3.0", + "build" : "21D62", + "type" : "macos" + }, + "id" : "44426D67-79AB-547C-7777-440AB8F5DDD2", + "ip" : [ + "fe80::bade:48ff:fe00:1122", + "fe81::4ab:9565:1199:be3", + "192.168.5.175", + "fe80::40d7:d0ff:fe66:f55", + "fe81::40d8:d0ff:fe66:f55", + "fe82::c2c:6bdf:3307:dce0", + "fe83::5069:fcd5:e31c:7059", + "fe80::ce81:b2c:bd2c:69e", + "fe80::febc:bbc1:c517:827b", + "fe80::6d09:bee6:55a5:539d", + "fe80::c920:752e:1e0e:edc9", + "fe80::a4a:ca38:761f:83e2" + ], + "mac" : [ + "ad:df:48:00:11:22", + "a6:86:e7:ae:5a:b6", + "a9:83:e7:ae:5a:b6", + "43:d8:d0:66:0f:55", + "42:d8:d0:66:0f:57", + "82:70:c7:c2:3c:01", + "82:70:c6:c2:4c:00", + "82:76:a6:c2:3c:05", + "82:70:c6:b2:3c:04", + "82:71:a6:c2:3c:01" + ], + "name" : "siem-kibana" + }, + "agent" : { + "type" : "winlogbeat", + "version" : "8.1.0", + "ephemeral_id" : "f6df090f-656a-4a79-a6a1-0c8671c9752d", + "id" : "0ebd469b-c164-4734-00e6-96d018098dc7", + "name" : "test.local" + }, + "event" : { + "module" : "sysmon", + "dataset" : "process", + "kind" : "event", + "category" : [ + "process" + ], + "type" : [ + "start" + ], + "action" : "process_started" + }, + "destination": { + "port": 80 + }, + "process" : { + "start" : "2022-03-04T19:41:34.902Z", + "pid" : 30884, + "working_directory" : "/Users/test/security_solution", + "hash" : { + "sha1" : "ae2d46c38fa207efbea5fcecd6294eebbf5af00f" + }, + "parent" : { + "pid" : 777 + }, + "executable" : "/bin/zsh", + "name" : "zsh", + "args" : [ + "-zsh", + "unique" + ], + "entity_id" : "q6pltOhTWlQx3BCE", + "entry_leader": { + "entity_id": "q6pltOhTWlQx3BCE", + "name": "fake entry", + "pid": 2342342 + } + }, + "message" : "Process zsh (PID: 27884) by user test STARTED", + "user" : { + "id" : "505", + "group" : { + "name" : "staff", + "id" : "20" + }, + "effective" : { + "id" : "505", + "group" : { + "id" : "20" + } + }, + "saved" : { + "id" : "505", + "group" : { + "id" : "20" + } + }, + "name" : "test" + }, + "service" : { + "type" : "system" + }, + "ecs" : { + "version" : "8.0.0" + } + } + } +} diff --git a/x-pack/test/security_solution_playwright/es_archives/auditbeat_single/mappings.json b/x-pack/test/security_solution_playwright/es_archives/auditbeat_single/mappings.json new file mode 100644 index 0000000000000..091dc0d33f6cd --- /dev/null +++ b/x-pack/test/security_solution_playwright/es_archives/auditbeat_single/mappings.json @@ -0,0 +1,7854 @@ +{ + "type": "index", + "value": { + "aliases": { + "auditbeat": { + "is_write_index": false + } + }, + "settings": { + "index": { + "refresh_interval": "5s" + }, + "index.mapping.total_fields.limit": 2000 + }, + "index": "auditbeat-2022", + "mappings": { + "date_detection": false, + "dynamic_templates" : [ + { + "labels" : { + "path_match" : "labels.*", + "match_mapping_type" : "string", + "mapping" : { + "type" : "keyword" + } + } + }, + { + "container.labels" : { + "path_match" : "container.labels.*", + "match_mapping_type" : "string", + "mapping" : { + "type" : "keyword" + } + } + }, + { + "fields" : { + "path_match" : "fields.*", + "match_mapping_type" : "string", + "mapping" : { + "type" : "keyword" + } + } + }, + { + "docker.container.labels" : { + "path_match" : "docker.container.labels.*", + "match_mapping_type" : "string", + "mapping" : { + "type" : "keyword" + } + } + }, + { + "kubernetes.labels.*" : { + "path_match" : "kubernetes.labels.*", + "mapping" : { + "type" : "keyword" + } + } + }, + { + "kubernetes.annotations.*" : { + "path_match" : "kubernetes.annotations.*", + "mapping" : { + "type" : "keyword" + } + } + }, + { + "kubernetes.selectors.*" : { + "path_match" : "kubernetes.selectors.*", + "mapping" : { + "type" : "keyword" + } + } + }, + { + "strings_as_keyword" : { + "match_mapping_type" : "string", + "mapping" : { + "ignore_above" : 1024, + "type" : "keyword" + } + } + } + ], + "properties" : { + "@timestamp" : { + "type" : "date" + }, + "agent" : { + "properties" : { + "build" : { + "properties" : { + "original" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "ephemeral_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "hostname" : { + "type" : "alias", + "path" : "agent.name" + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "as" : { + "properties" : { + "number" : { + "type" : "long" + }, + "organization" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + } + } + } + } + }, + "auditd" : { + "properties" : { + "data" : { + "properties" : { + "a0" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "a1" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "a2" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "a3" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "a[0-3]" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "acct" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "acl" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "action" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "added" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "addr" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "apparmor" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "arch" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "argc" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "audit_backlog_limit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "audit_backlog_wait_time" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "audit_enabled" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "audit_failure" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "banners" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "bool" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "bus" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "cap_fe" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "cap_fi" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "cap_fp" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "cap_fver" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "cap_pe" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "cap_pi" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "cap_pp" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "capability" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "cgroup" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "changed" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "cipher" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "class" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "cmd" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "compat" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "daddr" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "data" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "default-context" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "device" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "dir" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "direction" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "dmac" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "dport" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "enforcing" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "entries" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "exit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "fam" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "family" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "fd" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "fe" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "feature" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "fi" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "file" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "flags" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "format" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "fp" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "fver" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "grantors" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "grp" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "hook" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "hostname" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "icmp_type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "igid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "img-ctx" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "inif" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ino" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "inode_gid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "inode_uid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "invalid_context" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ioctlcmd" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ip" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ipid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ipx-net" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "items" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "iuid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "kernel" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "kind" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ksize" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "laddr" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "len" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "list" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "lport" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "mac" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "macproto" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "maj" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "major" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "minor" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "model" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "msg" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "nargs" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "net" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new-chardev" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new-disk" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new-enabled" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new-fs" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new-level" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new-log_passwd" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new-mem" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new-net" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new-range" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new-rng" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new-role" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new-seuser" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new-vcpu" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new_gid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new_lock" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new_pe" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new_pi" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "new_pp" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "nlnk-fam" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "nlnk-grp" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "nlnk-pid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "oauid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "obj" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "obj_gid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "obj_uid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ocomm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "oflag" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old-auid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old-chardev" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old-disk" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old-enabled" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old-fs" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old-level" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old-log_passwd" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old-mem" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old-net" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old-range" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old-rng" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old-role" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old-ses" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old-seuser" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old-vcpu" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old_enforcing" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old_lock" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old_pe" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old_pi" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old_pp" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old_prom" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "old_val" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "op" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "opid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "oses" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "outif" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "parent" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "per" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "perm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "perm_mask" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "permissive" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "pfs" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "printer" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "prom" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "proto" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "qbytes" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "range" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "reason" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "removed" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "res" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "resrc" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "rport" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sauid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "scontext" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "selected-context" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "seperm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "seperms" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "seqno" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "seresult" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ses" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "seuser" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sig" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sigev_signo" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "smac" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "socket" : { + "properties" : { + "addr" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "family" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "path" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "port" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "saddr" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "spid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sport" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "state" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subj" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "success" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "syscall" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "table" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "tclass" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "tcontext" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "terminal" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "tty" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "unit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "uri" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "uuid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "val" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ver" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "virt" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "vm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "vm-ctx" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "vm-pid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "watch" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "message_type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "paths" : { + "properties" : { + "dev" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "inode" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "item" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "mode" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "nametype" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "obj_domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "obj_level" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "obj_role" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "obj_user" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "objtype" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ogid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ouid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "rdev" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "result" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sequence" : { + "type" : "long" + }, + "session" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "summary" : { + "properties" : { + "actor" : { + "properties" : { + "primary" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "secondary" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "how" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "object" : { + "properties" : { + "primary" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "secondary" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + } + } + }, + "client" : { + "properties" : { + "address" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "as" : { + "properties" : { + "number" : { + "type" : "long" + }, + "organization" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + } + } + } + } + }, + "bytes" : { + "type" : "long" + }, + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "geo" : { + "properties" : { + "city_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "location" : { + "type" : "geo_point" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "postal_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "timezone" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "ip" : { + "type" : "ip" + }, + "mac" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "nat" : { + "properties" : { + "ip" : { + "type" : "ip" + }, + "port" : { + "type" : "long" + } + } + }, + "packets" : { + "type" : "long" + }, + "port" : { + "type" : "long" + }, + "registered_domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subdomain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "top_level_domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "user" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "email" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "full_name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "group" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "hash" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "roles" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "cloud" : { + "properties" : { + "account" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "availability_zone" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "image" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "instance" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "machine" : { + "properties" : { + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "origin" : { + "properties" : { + "account" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "availability_zone" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "instance" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "machine" : { + "properties" : { + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "project" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "provider" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "service" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "project" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "provider" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "service" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "target" : { + "properties" : { + "account" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "availability_zone" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "instance" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "machine" : { + "properties" : { + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "project" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "provider" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "service" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + } + } + }, + "code_signature" : { + "properties" : { + "digest_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "exists" : { + "type" : "boolean" + }, + "signing_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "status" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subject_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "team_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "timestamp" : { + "type" : "date" + }, + "trusted" : { + "type" : "boolean" + }, + "valid" : { + "type" : "boolean" + } + } + }, + "container" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "image" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "tag" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "labels" : { + "type" : "object" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "runtime" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "data_stream" : { + "properties" : { + "dataset" : { + "type" : "constant_keyword" + }, + "namespace" : { + "type" : "constant_keyword" + }, + "type" : { + "type" : "constant_keyword" + } + } + }, + "destination" : { + "properties" : { + "address" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "as" : { + "properties" : { + "number" : { + "type" : "long" + }, + "organization" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + } + } + } + } + }, + "bytes" : { + "type" : "long" + }, + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "geo" : { + "properties" : { + "city_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "location" : { + "type" : "geo_point" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "postal_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "timezone" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "ip" : { + "type" : "ip" + }, + "mac" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "nat" : { + "properties" : { + "ip" : { + "type" : "ip" + }, + "port" : { + "type" : "long" + } + } + }, + "packets" : { + "type" : "long" + }, + "path" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "port" : { + "type" : "long" + }, + "registered_domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subdomain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "top_level_domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "user" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "email" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "full_name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "group" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "hash" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "roles" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "dll" : { + "properties" : { + "code_signature" : { + "properties" : { + "digest_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "exists" : { + "type" : "boolean" + }, + "signing_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "status" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subject_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "team_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "timestamp" : { + "type" : "date" + }, + "trusted" : { + "type" : "boolean" + }, + "valid" : { + "type" : "boolean" + } + } + }, + "hash" : { + "properties" : { + "md5" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha1" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha256" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha512" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ssdeep" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "path" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "pe" : { + "properties" : { + "architecture" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "company" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "description" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "file_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "imphash" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "original_file_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "product" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "dns" : { + "properties" : { + "answers" : { + "properties" : { + "class" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "data" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ttl" : { + "type" : "long" + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "header_flags" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "op_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "question" : { + "properties" : { + "class" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "registered_domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subdomain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "top_level_domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "resolved_ip" : { + "type" : "ip" + }, + "response_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "docker" : { + "properties" : { + "container" : { + "properties" : { + "labels" : { + "type" : "object" + } + } + } + } + }, + "ecs" : { + "properties" : { + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "elf" : { + "properties" : { + "architecture" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "byte_order" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "cpu_type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "creation_date" : { + "type" : "date" + }, + "exports" : { + "type" : "flattened" + }, + "header" : { + "properties" : { + "abi_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "class" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "data" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "entrypoint" : { + "type" : "long" + }, + "object_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "os_abi" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "imports" : { + "type" : "flattened" + }, + "sections" : { + "type" : "nested", + "properties" : { + "chi2" : { + "type" : "long" + }, + "entropy" : { + "type" : "long" + }, + "flags" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "physical_offset" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "physical_size" : { + "type" : "long" + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "virtual_address" : { + "type" : "long" + }, + "virtual_size" : { + "type" : "long" + } + } + }, + "segments" : { + "type" : "nested", + "properties" : { + "sections" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "shared_libraries" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "telfhash" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "error" : { + "properties" : { + "code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "message" : { + "type" : "match_only_text" + }, + "stack_trace" : { + "type" : "wildcard", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "event" : { + "properties" : { + "action" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "agent_id_status" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "category" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "created" : { + "type" : "date" + }, + "dataset" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "duration" : { + "type" : "long" + }, + "end" : { + "type" : "date" + }, + "hash" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ingested" : { + "type" : "date" + }, + "kind" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "module" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "origin" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "original" : { + "type" : "keyword", + "index" : false, + "doc_values" : false, + "ignore_above" : 1024 + }, + "outcome" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "provider" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "reason" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "reference" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "risk_score" : { + "type" : "float" + }, + "risk_score_norm" : { + "type" : "float" + }, + "sequence" : { + "type" : "long" + }, + "severity" : { + "type" : "long" + }, + "start" : { + "type" : "date" + }, + "timezone" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "url" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "faas" : { + "properties" : { + "coldstart" : { + "type" : "boolean" + }, + "execution" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "trigger" : { + "type" : "nested", + "properties" : { + "request_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "fields" : { + "type" : "object" + }, + "file" : { + "properties" : { + "accessed" : { + "type" : "date" + }, + "attributes" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "code_signature" : { + "properties" : { + "digest_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "exists" : { + "type" : "boolean" + }, + "signing_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "status" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subject_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "team_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "timestamp" : { + "type" : "date" + }, + "trusted" : { + "type" : "boolean" + }, + "valid" : { + "type" : "boolean" + } + } + }, + "created" : { + "type" : "date" + }, + "ctime" : { + "type" : "date" + }, + "device" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "directory" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "drive_letter" : { + "type" : "keyword", + "ignore_above" : 1 + }, + "elf" : { + "properties" : { + "architecture" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "byte_order" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "cpu_type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "creation_date" : { + "type" : "date" + }, + "exports" : { + "type" : "flattened" + }, + "header" : { + "properties" : { + "abi_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "class" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "data" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "entrypoint" : { + "type" : "long" + }, + "object_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "os_abi" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "imports" : { + "type" : "flattened" + }, + "sections" : { + "type" : "nested", + "properties" : { + "chi2" : { + "type" : "long" + }, + "entropy" : { + "type" : "long" + }, + "flags" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "physical_offset" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "physical_size" : { + "type" : "long" + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "virtual_address" : { + "type" : "long" + }, + "virtual_size" : { + "type" : "long" + } + } + }, + "segments" : { + "type" : "nested", + "properties" : { + "sections" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "shared_libraries" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "telfhash" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "extension" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "fork_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "gid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "group" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "hash" : { + "properties" : { + "md5" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha1" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha256" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha512" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ssdeep" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "inode" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "mime_type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "mode" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "mtime" : { + "type" : "date" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "origin" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "text", + "norms" : false + } + } + }, + "owner" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "path" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "pe" : { + "properties" : { + "architecture" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "company" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "description" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "file_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "imphash" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "original_file_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "product" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "selinux" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "level" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "role" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "user" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "setgid" : { + "type" : "boolean" + }, + "setuid" : { + "type" : "boolean" + }, + "size" : { + "type" : "long" + }, + "target_path" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "uid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "x509" : { + "properties" : { + "alternative_names" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "issuer" : { + "properties" : { + "common_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "distinguished_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "locality" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organization" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organizational_unit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "state_or_province" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "not_after" : { + "type" : "date" + }, + "not_before" : { + "type" : "date" + }, + "public_key_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "public_key_curve" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "public_key_exponent" : { + "type" : "long", + "index" : false, + "doc_values" : false + }, + "public_key_size" : { + "type" : "long" + }, + "serial_number" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "signature_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subject" : { + "properties" : { + "common_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "distinguished_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "locality" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organization" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organizational_unit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "state_or_province" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "version_number" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "geo" : { + "properties" : { + "city_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "location" : { + "type" : "geo_point" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "postal_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "timezone" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "geoip" : { + "properties" : { + "city_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "location" : { + "type" : "geo_point" + }, + "region_name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "group" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "hash" : { + "properties" : { + "blake2b_256" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "blake2b_384" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "blake2b_512" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "md5" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha1" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha224" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha256" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha384" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha3_224" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha3_256" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha3_384" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha3_512" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha512" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha512_224" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha512_256" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ssdeep" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "xxh64" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "host" : { + "properties" : { + "architecture" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "containerized" : { + "type" : "boolean" + }, + "cpu" : { + "properties" : { + "usage" : { + "type" : "scaled_float", + "scaling_factor" : 1000.0 + } + } + }, + "disk" : { + "properties" : { + "read" : { + "properties" : { + "bytes" : { + "type" : "long" + } + } + }, + "write" : { + "properties" : { + "bytes" : { + "type" : "long" + } + } + } + } + }, + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "geo" : { + "properties" : { + "city_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "location" : { + "type" : "geo_point" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "postal_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "timezone" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "hostname" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ip" : { + "type" : "ip" + }, + "mac" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "network" : { + "properties" : { + "egress" : { + "properties" : { + "bytes" : { + "type" : "long" + }, + "packets" : { + "type" : "long" + } + } + }, + "ingress" : { + "properties" : { + "bytes" : { + "type" : "long" + }, + "packets" : { + "type" : "long" + } + } + } + } + }, + "os" : { + "properties" : { + "build" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "codename" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "family" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "full" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "kernel" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "platform" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "uptime" : { + "type" : "long" + } + } + }, + "http" : { + "properties" : { + "request" : { + "properties" : { + "body" : { + "properties" : { + "bytes" : { + "type" : "long" + }, + "content" : { + "type" : "wildcard", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + } + } + }, + "bytes" : { + "type" : "long" + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "method" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "mime_type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "referrer" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "response" : { + "properties" : { + "body" : { + "properties" : { + "bytes" : { + "type" : "long" + }, + "content" : { + "type" : "wildcard", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + } + } + }, + "bytes" : { + "type" : "long" + }, + "mime_type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "status_code" : { + "type" : "long" + } + } + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "interface" : { + "properties" : { + "alias" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "jolokia" : { + "properties" : { + "agent" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "secured" : { + "type" : "boolean" + }, + "server" : { + "properties" : { + "product" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "vendor" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "url" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "kubernetes" : { + "properties" : { + "annotations" : { + "properties" : { + "*" : { + "type" : "object" + } + } + }, + "container" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "deployment" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "labels" : { + "properties" : { + "*" : { + "type" : "object" + } + } + }, + "namespace" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "node" : { + "properties" : { + "hostname" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "pod" : { + "properties" : { + "ip" : { + "type" : "ip" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "uid" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "replicaset" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "selectors" : { + "properties" : { + "*" : { + "type" : "object" + } + } + }, + "statefulset" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "labels" : { + "type" : "object" + }, + "log" : { + "properties" : { + "file" : { + "properties" : { + "path" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "level" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "logger" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "origin" : { + "properties" : { + "file" : { + "properties" : { + "line" : { + "type" : "long" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "function" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "syslog" : { + "properties" : { + "facility" : { + "properties" : { + "code" : { + "type" : "long" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "priority" : { + "type" : "long" + }, + "severity" : { + "properties" : { + "code" : { + "type" : "long" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + } + } + }, + "message" : { + "type" : "match_only_text" + }, + "network" : { + "properties" : { + "application" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "bytes" : { + "type" : "long" + }, + "community_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "direction" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "forwarded_ip" : { + "type" : "ip" + }, + "iana_number" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "inner" : { + "properties" : { + "vlan" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "packets" : { + "type" : "long" + }, + "protocol" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "transport" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "vlan" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "observer" : { + "properties" : { + "egress" : { + "properties" : { + "interface" : { + "properties" : { + "alias" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "vlan" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "zone" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "geo" : { + "properties" : { + "city_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "location" : { + "type" : "geo_point" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "postal_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "timezone" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "hostname" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ingress" : { + "properties" : { + "interface" : { + "properties" : { + "alias" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "vlan" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "zone" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "ip" : { + "type" : "ip" + }, + "mac" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "os" : { + "properties" : { + "family" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "full" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "kernel" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "platform" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "product" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "serial_number" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "vendor" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "orchestrator" : { + "properties" : { + "api_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "cluster" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "url" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "namespace" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organization" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "resource" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "organization" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + } + } + }, + "os" : { + "properties" : { + "family" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "full" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "kernel" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "platform" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "package" : { + "properties" : { + "architecture" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "build_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "checksum" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "description" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "install_scope" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "installed" : { + "type" : "date" + }, + "license" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "path" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "reference" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "size" : { + "type" : "long" + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "pe" : { + "properties" : { + "architecture" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "company" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "description" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "file_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "imphash" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "original_file_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "product" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "process" : { + "properties" : { + "args" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "args_count" : { + "type" : "long" + }, + "code_signature" : { + "properties" : { + "digest_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "exists" : { + "type" : "boolean" + }, + "signing_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "status" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subject_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "team_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "timestamp" : { + "type" : "date" + }, + "trusted" : { + "type" : "boolean" + }, + "valid" : { + "type" : "boolean" + } + } + }, + "command_line" : { + "type" : "wildcard", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "elf" : { + "properties" : { + "architecture" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "byte_order" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "cpu_type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "creation_date" : { + "type" : "date" + }, + "exports" : { + "type" : "flattened" + }, + "header" : { + "properties" : { + "abi_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "class" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "data" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "entrypoint" : { + "type" : "long" + }, + "object_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "os_abi" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "imports" : { + "type" : "flattened" + }, + "sections" : { + "type" : "nested", + "properties" : { + "chi2" : { + "type" : "long" + }, + "entropy" : { + "type" : "long" + }, + "flags" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "physical_offset" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "physical_size" : { + "type" : "long" + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "virtual_address" : { + "type" : "long" + }, + "virtual_size" : { + "type" : "long" + } + } + }, + "segments" : { + "type" : "nested", + "properties" : { + "sections" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "shared_libraries" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "telfhash" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "end" : { + "type" : "date" + }, + "entity_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "executable" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "exit_code" : { + "type" : "long" + }, + "hash" : { + "properties" : { + "blake2b_256" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "blake2b_384" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "blake2b_512" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "md5" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha1" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha224" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha256" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha384" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha3_224" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha3_256" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha3_384" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha3_512" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha512" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha512_224" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha512_256" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ssdeep" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "xxh64" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "owner" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "text", + "norms" : false + } + } + } + } + }, + "parent" : { + "properties" : { + "args" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "args_count" : { + "type" : "long" + }, + "code_signature" : { + "properties" : { + "digest_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "exists" : { + "type" : "boolean" + }, + "signing_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "status" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subject_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "team_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "timestamp" : { + "type" : "date" + }, + "trusted" : { + "type" : "boolean" + }, + "valid" : { + "type" : "boolean" + } + } + }, + "command_line" : { + "type" : "wildcard", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "elf" : { + "properties" : { + "architecture" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "byte_order" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "cpu_type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "creation_date" : { + "type" : "date" + }, + "exports" : { + "type" : "flattened" + }, + "header" : { + "properties" : { + "abi_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "class" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "data" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "entrypoint" : { + "type" : "long" + }, + "object_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "os_abi" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "imports" : { + "type" : "flattened" + }, + "sections" : { + "type" : "nested", + "properties" : { + "chi2" : { + "type" : "long" + }, + "entropy" : { + "type" : "long" + }, + "flags" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "physical_offset" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "physical_size" : { + "type" : "long" + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "virtual_address" : { + "type" : "long" + }, + "virtual_size" : { + "type" : "long" + } + } + }, + "segments" : { + "type" : "nested", + "properties" : { + "sections" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "shared_libraries" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "telfhash" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "end" : { + "type" : "date" + }, + "entity_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "executable" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "exit_code" : { + "type" : "long" + }, + "hash" : { + "properties" : { + "md5" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha1" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha256" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha512" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ssdeep" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "pe" : { + "properties" : { + "architecture" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "company" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "description" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "file_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "imphash" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "original_file_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "product" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "pgid" : { + "type" : "long" + }, + "pid" : { + "type" : "long" + }, + "start" : { + "type" : "date" + }, + "thread" : { + "properties" : { + "id" : { + "type" : "long" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "title" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "uptime" : { + "type" : "long" + }, + "working_directory" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + } + } + }, + "pe" : { + "properties" : { + "architecture" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "company" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "description" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "file_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "imphash" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "original_file_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "product" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "pgid" : { + "type" : "long" + }, + "pid" : { + "type" : "long" + }, + "start" : { + "type" : "date" + }, + "thread" : { + "properties" : { + "id" : { + "type" : "long" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "title" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "uptime" : { + "type" : "long" + }, + "working_directory" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + } + } + }, + "registry" : { + "properties" : { + "data" : { + "properties" : { + "bytes" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "strings" : { + "type" : "wildcard", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "hive" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "key" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "path" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "value" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "related" : { + "properties" : { + "hash" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "hosts" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ip" : { + "type" : "ip" + }, + "user" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "rule" : { + "properties" : { + "author" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "category" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "description" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "license" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "reference" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ruleset" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "uuid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "server" : { + "properties" : { + "address" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "as" : { + "properties" : { + "number" : { + "type" : "long" + }, + "organization" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + } + } + } + } + }, + "bytes" : { + "type" : "long" + }, + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "geo" : { + "properties" : { + "city_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "location" : { + "type" : "geo_point" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "postal_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "timezone" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "ip" : { + "type" : "ip" + }, + "mac" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "nat" : { + "properties" : { + "ip" : { + "type" : "ip" + }, + "port" : { + "type" : "long" + } + } + }, + "packets" : { + "type" : "long" + }, + "port" : { + "type" : "long" + }, + "registered_domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subdomain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "top_level_domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "user" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "email" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "full_name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "group" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "hash" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "roles" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "service" : { + "properties" : { + "address" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "environment" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ephemeral_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "node" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "origin" : { + "properties" : { + "address" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "environment" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ephemeral_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "node" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "state" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "state" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "target" : { + "properties" : { + "address" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "environment" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ephemeral_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "node" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "state" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "socket" : { + "properties" : { + "entity_id" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "source" : { + "properties" : { + "address" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "as" : { + "properties" : { + "number" : { + "type" : "long" + }, + "organization" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + } + } + } + } + }, + "bytes" : { + "type" : "long" + }, + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "geo" : { + "properties" : { + "city_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "location" : { + "type" : "geo_point" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "postal_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "timezone" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "ip" : { + "type" : "ip" + }, + "mac" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "nat" : { + "properties" : { + "ip" : { + "type" : "ip" + }, + "port" : { + "type" : "long" + } + } + }, + "packets" : { + "type" : "long" + }, + "path" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "port" : { + "type" : "long" + }, + "registered_domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subdomain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "top_level_domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "user" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "email" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "full_name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "group" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "hash" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "roles" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "span" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "system" : { + "properties" : { + "audit" : { + "properties" : { + "host" : { + "properties" : { + "architecture" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "boottime" : { + "type" : "date" + }, + "containerized" : { + "type" : "boolean" + }, + "hostname" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ip" : { + "type" : "ip" + }, + "mac" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "os" : { + "properties" : { + "codename" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "family" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "kernel" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "platform" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "timezone" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "offset" : { + "properties" : { + "sec" : { + "type" : "long" + } + } + } + } + }, + "uptime" : { + "type" : "long" + } + } + }, + "package" : { + "properties" : { + "arch" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "entity_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "installtime" : { + "type" : "date" + }, + "license" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "release" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "size" : { + "type" : "long" + }, + "summary" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "url" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "user" : { + "properties" : { + "dir" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "gid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "group" : { + "type" : "object" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "password" : { + "properties" : { + "last_changed" : { + "type" : "date" + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "shell" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "uid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "user_information" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + } + } + }, + "tags" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "threat" : { + "properties" : { + "enrichments" : { + "type" : "nested", + "properties" : { + "indicator" : { + "properties" : { + "as" : { + "properties" : { + "number" : { + "type" : "long" + }, + "organization" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + } + } + } + } + }, + "confidence" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "description" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "email" : { + "properties" : { + "address" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "file" : { + "properties" : { + "accessed" : { + "type" : "date" + }, + "attributes" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "code_signature" : { + "properties" : { + "digest_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "exists" : { + "type" : "boolean" + }, + "signing_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "status" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subject_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "team_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "timestamp" : { + "type" : "date" + }, + "trusted" : { + "type" : "boolean" + }, + "valid" : { + "type" : "boolean" + } + } + }, + "created" : { + "type" : "date" + }, + "ctime" : { + "type" : "date" + }, + "device" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "directory" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "drive_letter" : { + "type" : "keyword", + "ignore_above" : 1 + }, + "elf" : { + "properties" : { + "architecture" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "byte_order" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "cpu_type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "creation_date" : { + "type" : "date" + }, + "exports" : { + "type" : "flattened" + }, + "header" : { + "properties" : { + "abi_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "class" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "data" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "entrypoint" : { + "type" : "long" + }, + "object_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "os_abi" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "imports" : { + "type" : "flattened" + }, + "sections" : { + "type" : "nested", + "properties" : { + "chi2" : { + "type" : "long" + }, + "entropy" : { + "type" : "long" + }, + "flags" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "physical_offset" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "physical_size" : { + "type" : "long" + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "virtual_address" : { + "type" : "long" + }, + "virtual_size" : { + "type" : "long" + } + } + }, + "segments" : { + "type" : "nested", + "properties" : { + "sections" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "shared_libraries" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "telfhash" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "extension" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "fork_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "gid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "group" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "hash" : { + "properties" : { + "md5" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha1" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha256" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha512" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ssdeep" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "inode" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "mime_type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "mode" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "mtime" : { + "type" : "date" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "owner" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "path" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "pe" : { + "properties" : { + "architecture" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "company" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "description" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "file_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "imphash" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "original_file_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "product" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "size" : { + "type" : "long" + }, + "target_path" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "uid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "x509" : { + "properties" : { + "alternative_names" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "issuer" : { + "properties" : { + "common_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "distinguished_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "locality" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organization" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organizational_unit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "state_or_province" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "not_after" : { + "type" : "date" + }, + "not_before" : { + "type" : "date" + }, + "public_key_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "public_key_curve" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "public_key_exponent" : { + "type" : "long", + "index" : false, + "doc_values" : false + }, + "public_key_size" : { + "type" : "long" + }, + "serial_number" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "signature_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subject" : { + "properties" : { + "common_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "distinguished_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "locality" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organization" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organizational_unit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "state_or_province" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "version_number" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "first_seen" : { + "type" : "date" + }, + "geo" : { + "properties" : { + "city_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "location" : { + "type" : "geo_point" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "postal_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "timezone" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "ip" : { + "type" : "ip" + }, + "last_seen" : { + "type" : "date" + }, + "marking" : { + "properties" : { + "tlp" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "modified_at" : { + "type" : "date" + }, + "port" : { + "type" : "long" + }, + "provider" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "reference" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "registry" : { + "properties" : { + "data" : { + "properties" : { + "bytes" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "strings" : { + "type" : "wildcard", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "hive" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "key" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "path" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "value" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "scanner_stats" : { + "type" : "long" + }, + "sightings" : { + "type" : "long" + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "url" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "extension" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "fragment" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "full" : { + "type" : "wildcard", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "original" : { + "type" : "wildcard", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "password" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "path" : { + "type" : "wildcard", + "ignore_above" : 1024 + }, + "port" : { + "type" : "long" + }, + "query" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "registered_domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "scheme" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subdomain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "top_level_domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "username" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "x509" : { + "properties" : { + "alternative_names" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "issuer" : { + "properties" : { + "common_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "distinguished_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "locality" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organization" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organizational_unit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "state_or_province" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "not_after" : { + "type" : "date" + }, + "not_before" : { + "type" : "date" + }, + "public_key_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "public_key_curve" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "public_key_exponent" : { + "type" : "long", + "index" : false, + "doc_values" : false + }, + "public_key_size" : { + "type" : "long" + }, + "serial_number" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "signature_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subject" : { + "properties" : { + "common_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "distinguished_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "locality" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organization" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organizational_unit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "state_or_province" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "version_number" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "matched" : { + "properties" : { + "atomic" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "field" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "index" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "framework" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "group" : { + "properties" : { + "alias" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "reference" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "indicator" : { + "properties" : { + "as" : { + "properties" : { + "number" : { + "type" : "long" + }, + "organization" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + } + } + } + } + }, + "confidence" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "description" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "email" : { + "properties" : { + "address" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "file" : { + "properties" : { + "accessed" : { + "type" : "date" + }, + "attributes" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "code_signature" : { + "properties" : { + "digest_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "exists" : { + "type" : "boolean" + }, + "signing_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "status" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subject_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "team_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "timestamp" : { + "type" : "date" + }, + "trusted" : { + "type" : "boolean" + }, + "valid" : { + "type" : "boolean" + } + } + }, + "created" : { + "type" : "date" + }, + "ctime" : { + "type" : "date" + }, + "device" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "directory" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "drive_letter" : { + "type" : "keyword", + "ignore_above" : 1 + }, + "elf" : { + "properties" : { + "architecture" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "byte_order" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "cpu_type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "creation_date" : { + "type" : "date" + }, + "exports" : { + "type" : "flattened" + }, + "header" : { + "properties" : { + "abi_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "class" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "data" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "entrypoint" : { + "type" : "long" + }, + "object_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "os_abi" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "imports" : { + "type" : "flattened" + }, + "sections" : { + "type" : "nested", + "properties" : { + "chi2" : { + "type" : "long" + }, + "entropy" : { + "type" : "long" + }, + "flags" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "physical_offset" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "physical_size" : { + "type" : "long" + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "virtual_address" : { + "type" : "long" + }, + "virtual_size" : { + "type" : "long" + } + } + }, + "segments" : { + "type" : "nested", + "properties" : { + "sections" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "shared_libraries" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "telfhash" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "extension" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "fork_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "gid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "group" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "hash" : { + "properties" : { + "md5" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha1" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha256" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha512" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ssdeep" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "inode" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "mime_type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "mode" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "mtime" : { + "type" : "date" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "owner" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "path" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "pe" : { + "properties" : { + "architecture" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "company" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "description" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "file_version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "imphash" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "original_file_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "product" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "size" : { + "type" : "long" + }, + "target_path" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "uid" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "x509" : { + "properties" : { + "alternative_names" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "issuer" : { + "properties" : { + "common_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "distinguished_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "locality" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organization" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organizational_unit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "state_or_province" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "not_after" : { + "type" : "date" + }, + "not_before" : { + "type" : "date" + }, + "public_key_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "public_key_curve" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "public_key_exponent" : { + "type" : "long", + "index" : false, + "doc_values" : false + }, + "public_key_size" : { + "type" : "long" + }, + "serial_number" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "signature_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subject" : { + "properties" : { + "common_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "distinguished_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "locality" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organization" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organizational_unit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "state_or_province" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "version_number" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "first_seen" : { + "type" : "date" + }, + "geo" : { + "properties" : { + "city_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "continent_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "location" : { + "type" : "geo_point" + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "postal_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_iso_code" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "region_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "timezone" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "ip" : { + "type" : "ip" + }, + "last_seen" : { + "type" : "date" + }, + "marking" : { + "properties" : { + "tlp" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "modified_at" : { + "type" : "date" + }, + "port" : { + "type" : "long" + }, + "provider" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "reference" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "registry" : { + "properties" : { + "data" : { + "properties" : { + "bytes" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "strings" : { + "type" : "wildcard", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "hive" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "key" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "path" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "value" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "scanner_stats" : { + "type" : "long" + }, + "sightings" : { + "type" : "long" + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "url" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "extension" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "fragment" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "full" : { + "type" : "wildcard", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "original" : { + "type" : "wildcard", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "password" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "path" : { + "type" : "wildcard", + "ignore_above" : 1024 + }, + "port" : { + "type" : "long" + }, + "query" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "registered_domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "scheme" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subdomain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "top_level_domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "username" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "x509" : { + "properties" : { + "alternative_names" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "issuer" : { + "properties" : { + "common_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "distinguished_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "locality" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organization" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organizational_unit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "state_or_province" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "not_after" : { + "type" : "date" + }, + "not_before" : { + "type" : "date" + }, + "public_key_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "public_key_curve" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "public_key_exponent" : { + "type" : "long", + "index" : false, + "doc_values" : false + }, + "public_key_size" : { + "type" : "long" + }, + "serial_number" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "signature_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subject" : { + "properties" : { + "common_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "distinguished_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "locality" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organization" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organizational_unit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "state_or_province" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "version_number" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "software" : { + "properties" : { + "alias" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "platforms" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "reference" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "tactic" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "reference" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "technique" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "reference" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subtechnique" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "reference" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + } + } + }, + "timeseries" : { + "properties" : { + "instance" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "tls" : { + "properties" : { + "cipher" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "client" : { + "properties" : { + "certificate" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "certificate_chain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "hash" : { + "properties" : { + "md5" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha1" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha256" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "issuer" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ja3" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "not_after" : { + "type" : "date" + }, + "not_before" : { + "type" : "date" + }, + "server_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subject" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "supported_ciphers" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "x509" : { + "properties" : { + "alternative_names" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "issuer" : { + "properties" : { + "common_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "distinguished_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "locality" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organization" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organizational_unit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "state_or_province" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "not_after" : { + "type" : "date" + }, + "not_before" : { + "type" : "date" + }, + "public_key_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "public_key_curve" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "public_key_exponent" : { + "type" : "long", + "index" : false, + "doc_values" : false + }, + "public_key_size" : { + "type" : "long" + }, + "serial_number" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "signature_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subject" : { + "properties" : { + "common_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "distinguished_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "locality" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organization" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organizational_unit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "state_or_province" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "version_number" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "curve" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "established" : { + "type" : "boolean" + }, + "next_protocol" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "resumed" : { + "type" : "boolean" + }, + "server" : { + "properties" : { + "certificate" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "certificate_chain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "hash" : { + "properties" : { + "md5" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha1" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "sha256" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "issuer" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "ja3s" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "not_after" : { + "type" : "date" + }, + "not_before" : { + "type" : "date" + }, + "subject" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "x509" : { + "properties" : { + "alternative_names" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "issuer" : { + "properties" : { + "common_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "distinguished_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "locality" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organization" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organizational_unit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "state_or_province" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "not_after" : { + "type" : "date" + }, + "not_before" : { + "type" : "date" + }, + "public_key_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "public_key_curve" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "public_key_exponent" : { + "type" : "long", + "index" : false, + "doc_values" : false + }, + "public_key_size" : { + "type" : "long" + }, + "serial_number" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "signature_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subject" : { + "properties" : { + "common_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "distinguished_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "locality" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organization" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organizational_unit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "state_or_province" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "version_number" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version_protocol" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "trace" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "transaction" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "url" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "extension" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "fragment" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "full" : { + "type" : "wildcard", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "original" : { + "type" : "wildcard", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "password" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "path" : { + "type" : "wildcard", + "ignore_above" : 1024 + }, + "port" : { + "type" : "long" + }, + "query" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "registered_domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "scheme" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subdomain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "top_level_domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "username" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "user" : { + "properties" : { + "audit" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "changes" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "email" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "full_name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "group" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "hash" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "roles" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "effective" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "email" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "full_name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "group" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "hash" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "roles" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "email" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "entity_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "filesystem" : { + "properties" : { + "group" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "full_name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "group" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "hash" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "roles" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "saved" : { + "properties" : { + "group" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "selinux" : { + "properties" : { + "category" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "level" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "role" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "user" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "target" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "email" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "full_name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "group" : { + "properties" : { + "domain" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "hash" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "roles" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "terminal" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "user_agent" : { + "properties" : { + "device" : { + "properties" : { + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "original" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "os" : { + "properties" : { + "family" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "full" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "kernel" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "platform" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "type" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "vlan" : { + "properties" : { + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "name" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "vulnerability" : { + "properties" : { + "category" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "classification" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "description" : { + "type" : "keyword", + "ignore_above" : 1024, + "fields" : { + "text" : { + "type" : "match_only_text" + } + } + }, + "enumeration" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "reference" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "report_id" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "scanner" : { + "properties" : { + "vendor" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "score" : { + "properties" : { + "base" : { + "type" : "float" + }, + "environmental" : { + "type" : "float" + }, + "temporal" : { + "type" : "float" + }, + "version" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "severity" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "x509" : { + "properties" : { + "alternative_names" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "issuer" : { + "properties" : { + "common_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "distinguished_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "locality" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organization" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organizational_unit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "state_or_province" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "not_after" : { + "type" : "date" + }, + "not_before" : { + "type" : "date" + }, + "public_key_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "public_key_curve" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "public_key_exponent" : { + "type" : "long", + "index" : false, + "doc_values" : false + }, + "public_key_size" : { + "type" : "long" + }, + "serial_number" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "signature_algorithm" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "subject" : { + "properties" : { + "common_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "country" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "distinguished_name" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "locality" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organization" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "organizational_unit" : { + "type" : "keyword", + "ignore_above" : 1024 + }, + "state_or_province" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + }, + "version_number" : { + "type" : "keyword", + "ignore_above" : 1024 + } + } + } + } + } + } +} diff --git a/x-pack/test/security_solution_playwright/fixtures/es_archiver.ts b/x-pack/test/security_solution_playwright/fixtures/es_archiver.ts new file mode 100644 index 0000000000000..f51b2bf3464bc --- /dev/null +++ b/x-pack/test/security_solution_playwright/fixtures/es_archiver.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import Fs from 'fs'; +import * as Url from 'url'; +import { EsArchiver } from '@kbn/es-archiver'; +import { createEsClientForTesting, KbnClient, systemIndicesSuperuser } from '@kbn/test'; +import { ToolingLog } from '@kbn/tooling-log'; +import { CA_CERT_PATH } from '@kbn/dev-utils'; + +export const createEsArchiver = async () => { + const log = new ToolingLog({ level: 'verbose', writeTo: process.stdout }); + + const isServerless = process.env.IS_SERVERLESS === 'true'; + const isCloudServerless = process.env.CLOUD_SERVERLESS === 'true'; + + const serverlessCloudUser = { + username: process.env.ELASTICSEARCH_USERNAME ?? '', + password: process.env.ELASTICSEARCH_PASSWORD ?? '', + }; + + if (isServerless && (!serverlessCloudUser.username || !serverlessCloudUser.password)) { + throw new Error( + 'ELASTICSEARCH_USERNAME and ELASTICSEARCH_PASSWORD must be defined for serverless configuration' + ); + } + + let authOverride; + if (isServerless) { + authOverride = isCloudServerless ? serverlessCloudUser : systemIndicesSuperuser; + } + + const esUrl = process.env.ELASTICSEARCH_URL; + if (!esUrl) { + throw new Error('ELASTICSEARCH_URL environment variable is not set'); + } + + const client = createEsClientForTesting({ + esUrl: Url.format(new URL(esUrl)), + authOverride, + }); + + const kibanaUrl = process.env.KIBANA_URL || process.env.BASE_URL; + + const kbnClient = new KbnClient({ + log, + url: kibanaUrl as string, + ...(esUrl.includes('https') ? { certificateAuthorities: [Fs.readFileSync(CA_CERT_PATH)] } : {}), + }); + + return new EsArchiver({ + log, + client, + kbnClient, + baseDir: './es_archives', + }); +}; diff --git a/x-pack/test/security_solution_playwright/fixtures/saml.ts b/x-pack/test/security_solution_playwright/fixtures/saml.ts new file mode 100644 index 0000000000000..4b6eaccd34fba --- /dev/null +++ b/x-pack/test/security_solution_playwright/fixtures/saml.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { test as base } from '@playwright/test'; +import { ToolingLog } from '@kbn/tooling-log'; +import { HostOptions, SamlSessionManager } from '@kbn/test'; +import { resolve } from 'path'; +import { REPO_ROOT } from '@kbn/repo-info'; + +export const test = base.extend({ + samlSessionManager: async ({}, use) => { + const log = new ToolingLog({ level: 'verbose', writeTo: process.stdout }); + + const kbnHost = process.env.KIBANA_URL || process.env.BASE_URL; + const kbnUrl = new URL(kbnHost!); + + const hostOptions: HostOptions = { + protocol: kbnUrl.protocol as 'http' | 'https', + hostname: kbnUrl.hostname, + port: parseInt(kbnUrl.port, 10), + username: process.env.ELASTICSEARCH_USERNAME ?? '', + password: process.env.ELASTICSEARCH_PASSWORD ?? '', + }; + + const rolesFilename = process.env.PROXY_ORG ? `${process.env.PROXY_ORG}.json` : undefined; + const cloudUsersFilePath = resolve(REPO_ROOT, '.ftr', rolesFilename ?? 'role_users.json'); + + const samlSessionManager = new SamlSessionManager({ + hostOptions, + log, + isCloud: process.env.CLOUD_SERVERLESS === 'true', + cloudUsersFilePath, + }); + + await use(samlSessionManager); + }, +}); diff --git a/x-pack/test/security_solution_playwright/index.d.ts b/x-pack/test/security_solution_playwright/index.d.ts new file mode 100644 index 0000000000000..6b6ef5bce03df --- /dev/null +++ b/x-pack/test/security_solution_playwright/index.d.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +declare module '@kbn/repo-info' { + export const REPO_ROOT: string; +} +declare global { + const ReadableStream: any; +} diff --git a/x-pack/test/security_solution_playwright/package.json b/x-pack/test/security_solution_playwright/package.json new file mode 100644 index 0000000000000..10b1c01fb8fb3 --- /dev/null +++ b/x-pack/test/security_solution_playwright/package.json @@ -0,0 +1,15 @@ +{ + "author": "Elastic", + "name": "security_solution_playwright", + "version": "1.0.0", + "private": true, + "license": "Elastic License 2.0", + "scripts": { + "playwright:open": "node ../../plugins/security_solution/scripts/run_playwright/start_playwright open --config-file ../../test/security_solution_playwright/playwright.config.ts", + "playwright:run": "node ../../plugins/security_solution/scripts/run_playwright/start_playwright run --config-file ../../test/security_solution_playwright/playwright.config.ts", + "open:ess": "npm run playwright:open -- --ftr-config-file ../security_solution_cypress/cli_config", + "run:ess": "npm run playwright:run -- --ftr-config-file ../security_solution_cypress/cli_config", + "open:serverless": "npm run playwright:open -- --ftr-config-file ../security_solution_cypress/serverless_config", + "run:serverless": "npm run playwright:run -- --ftr-config-file ../security_solution_cypress/serverless_config" + } +} \ No newline at end of file diff --git a/x-pack/test/security_solution_playwright/page_objects/entity_analytics_management_po.ts b/x-pack/test/security_solution_playwright/page_objects/entity_analytics_management_po.ts new file mode 100644 index 0000000000000..0c8055b2d24d6 --- /dev/null +++ b/x-pack/test/security_solution_playwright/page_objects/entity_analytics_management_po.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Locator, Page } from '@playwright/test'; + +const PAGE_TITLE = '[data-test-subj="entityAnalyticsManagementPageTitle"]'; + +export class EntityAnalyticsManagementPage { + page: Page; + entityAnalyticsManagementPageTitle!: Locator; + + constructor(page: Page) { + this.page = page; + } + + async initialize() { + this.entityAnalyticsManagementPageTitle = this.page.locator(PAGE_TITLE); + } +} diff --git a/x-pack/test/security_solution_playwright/page_objects/entity_analytics_po.ts b/x-pack/test/security_solution_playwright/page_objects/entity_analytics_po.ts new file mode 100644 index 0000000000000..36e8a603ecd9a --- /dev/null +++ b/x-pack/test/security_solution_playwright/page_objects/entity_analytics_po.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Locator, Page, expect } from '@playwright/test'; +import { EntityAnalyticsManagementPage } from './entity_analytics_management_po'; +import { PageFactory } from './page_factory'; + +const PAGE_URL = '/app/security/entity_analytics'; +const ENABLE_HOST_RISK_SCORE_BUTTON = '[data-test-subj="enable_host_risk_score"]'; +const ENABLE_USER_RISK_SCORE_BUTTON = '[data-test-subj="enable_user_risk_score"]'; + +export class EntityAnalyticsPage { + page: Page; + enableHostRiskScoreBtn!: Locator; + enableUserRiskScoreBtn!: Locator; + + constructor(page: Page) { + this.page = page; + } + + async initialize() { + this.enableHostRiskScoreBtn = this.page.locator(ENABLE_HOST_RISK_SCORE_BUTTON); + this.enableUserRiskScoreBtn = this.page.locator(ENABLE_USER_RISK_SCORE_BUTTON); + } + + async navigates() { + await this.page.goto(PAGE_URL); + } + + async enableHostRisk(): Promise { + await this.enableHostRiskScoreBtn.click(); + return await PageFactory.createEntityAnalyticsManagementPage(this.page); + } + + async enableUserRisk(): Promise { + await this.enableUserRiskScoreBtn.click(); + return await PageFactory.createEntityAnalyticsManagementPage(this.page); + } + + async waitForEnableHostRiskScoreToBePresent() { + await expect(this.enableHostRiskScoreBtn).toBeVisible(); + } + + async waitForEnableUserRiskScoreToBePresent() { + await expect(this.enableUserRiskScoreBtn).toBeVisible(); + } +} diff --git a/x-pack/test/security_solution_playwright/page_objects/page_factory.ts b/x-pack/test/security_solution_playwright/page_objects/page_factory.ts new file mode 100644 index 0000000000000..6ac5a36638eb3 --- /dev/null +++ b/x-pack/test/security_solution_playwright/page_objects/page_factory.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 { Page } from '@playwright/test'; +import { EntityAnalyticsPage } from './entity_analytics_po'; +import { EntityAnalyticsManagementPage } from './entity_analytics_management_po'; +import { RuleDetailsPage } from './rule_details_page_po'; +import { RuleManagementPage } from './rule_management_po'; + +export class PageFactory { + static async createEntityAnalyticsPage(page: Page): Promise { + const entityAnalyticsPage = new EntityAnalyticsPage(page); + await entityAnalyticsPage.initialize(); + return entityAnalyticsPage; + } + + static async createEntityAnalyticsManagementPage( + page: Page + ): Promise { + const entityAnalyticsManagementPage = new EntityAnalyticsManagementPage(page); + await entityAnalyticsManagementPage.initialize(); + return entityAnalyticsManagementPage; + } + + static async createRuleDetailsPage(page: Page): Promise { + const ruleDetailsPage = new RuleDetailsPage(page); + await ruleDetailsPage.initialize(); + return ruleDetailsPage; + } + + static async createRuleManagementPage(page: Page): Promise { + const ruleManagementPage = new RuleManagementPage(page); + await ruleManagementPage.initialize(); + return ruleManagementPage; + } +} diff --git a/x-pack/test/security_solution_playwright/page_objects/rule_details_page_po.ts b/x-pack/test/security_solution_playwright/page_objects/rule_details_page_po.ts new file mode 100644 index 0000000000000..83d0c7821603c --- /dev/null +++ b/x-pack/test/security_solution_playwright/page_objects/rule_details_page_po.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Locator, Page } from '@playwright/test'; + +const PAGE_URL = '/app/security/rules/id/'; + +const POPOVER_ACTIONS_TRIGGER_BUTTON = '[data-test-subj="rules-details-popover-button-icon"]'; +const RULE_DETAILS_MANUAL_RULE_RUN_BTN = '[data-test-subj="rules-details-manual-rule-run"]'; +const MODAL_CONFIRMATION_BTN = '[data-test-subj="confirmModalConfirmButton"]'; +const TOASTER = '[data-test-subj="euiToastHeader"]'; + +export class RuleDetailsPage { + page: Page; + popoverActionsTriggerButton!: Locator; + ruleDetailsManualRuleRunButton!: Locator; + modalConfirmationBtn!: Locator; + toaster!: Locator; + + constructor(page: Page) { + this.page = page; + } + + async initialize() { + this.popoverActionsTriggerButton = this.page.locator(POPOVER_ACTIONS_TRIGGER_BUTTON); + this.ruleDetailsManualRuleRunButton = this.page.locator(RULE_DETAILS_MANUAL_RULE_RUN_BTN); + this.modalConfirmationBtn = this.page.locator(MODAL_CONFIRMATION_BTN); + this.toaster = this.page.locator(TOASTER); + } + + async navigateTo(ruleId: string) { + await this.page.goto(`${PAGE_URL}${ruleId}`); + } + + async manualRuleRun() { + await this.popoverActionsTriggerButton.click(); + await this.ruleDetailsManualRuleRunButton.click(); + await this.modalConfirmationBtn.click(); + } +} diff --git a/x-pack/test/security_solution_playwright/page_objects/rule_management_po.ts b/x-pack/test/security_solution_playwright/page_objects/rule_management_po.ts new file mode 100644 index 0000000000000..d8f3ab18e7b92 --- /dev/null +++ b/x-pack/test/security_solution_playwright/page_objects/rule_management_po.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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, Locator, Page } from '@playwright/test'; + +const PAGE_URL = '/app/security/rules/management'; + +const AUTO_REFRESH_POPOVER_TRIGGER_BUTTON = '[data-test-subj="autoRefreshButton"]'; +const REFRESH_SETTINGS_SWITCH = '[data-test-subj="refreshSettingsSwitch"]'; +const COLLAPSED_ACTION_BTN = '[data-test-subj="euiCollapsedItemActionsButton"]'; +const MANUAL_RULE_RUN_ACTION_BTN = '[data-test-subj="manualRuleRunAction"]'; +const MODAL_CONFIRMATION_BTN = '[data-test-subj="confirmModalConfirmButton"]'; +const TOASTER = '[data-test-subj="euiToastHeader"]'; + +export class RuleManagementPage { + page: Page; + autoRefreshPopoverTriggerButton!: Locator; + refreshSettingsSwitch!: Locator; + collapsedActionBtn!: Locator; + manualRuleRunActionBtn!: Locator; + modalConfirmationBtn!: Locator; + toaster!: Locator; + + constructor(page: Page) { + this.page = page; + } + + async initialize() { + this.autoRefreshPopoverTriggerButton = this.page.locator(AUTO_REFRESH_POPOVER_TRIGGER_BUTTON); + this.refreshSettingsSwitch = this.page.locator(REFRESH_SETTINGS_SWITCH); + this.collapsedActionBtn = this.page.locator(COLLAPSED_ACTION_BTN); + this.manualRuleRunActionBtn = this.page.locator(MANUAL_RULE_RUN_ACTION_BTN); + this.modalConfirmationBtn = this.page.locator(MODAL_CONFIRMATION_BTN); + this.toaster = this.page.locator(TOASTER); + } + + async navigate() { + await this.page.goto(PAGE_URL); + } + + async disableAutoRefresh() { + await this.autoRefreshPopoverTriggerButton.click(); + await this.refreshSettingsSwitch.click(); + } + + async manuallyRunFirstRule() { + await this.collapsedActionBtn.first().click(); + await expect(this.manualRuleRunActionBtn).toBeVisible(); + await this.manualRuleRunActionBtn.click(); + await this.modalConfirmationBtn.click(); + } +} diff --git a/x-pack/test/security_solution_playwright/playwright.config.ts b/x-pack/test/security_solution_playwright/playwright.config.ts new file mode 100644 index 0000000000000..8def75a155f2a --- /dev/null +++ b/x-pack/test/security_solution_playwright/playwright.config.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { defineConfig, devices } from '@playwright/test'; +import path from 'path'; +import { ReadableStream as PolyfillReadableStream } from 'web-streams-polyfill'; +import dotenv from 'dotenv'; + +(globalThis as any).ReadableStream = PolyfillReadableStream; + +dotenv.config({ path: path.resolve(__dirname, './.env') }); + +export default defineConfig({ + timeout: 60000, + expect: { timeout: 60000 }, + testDir: './tests/', + testMatch: process.env.FILE_PATH || '**/*.spec.ts', + fullyParallel: false, + forbidOnly: !!process.env.CI, + retries: 0, + workers: 1, + reporter: [['list', { printSteps: true }]], + use: { + trace: 'on-first-retry', + ignoreHTTPSErrors: true, + baseURL: process.env.KIBANA_URL, + bypassCSP: true, + actionTimeout: 60000, + navigationTimeout: 60000, + screenshot: 'only-on-failure', + launchOptions: { + args: ['--disable-web-security'], + }, + }, + projects: [ + { + name: 'login_ess', + testMatch: '**/setup/login_ess.ts', + }, + { + name: 'login_serverless', + testMatch: '**/setup/login_serverless.ts', + }, + { + name: 'ess', + use: { ...devices['Desktop Chrome'] }, + dependencies: ['login_ess'], + }, + { + name: 'serverless', + use: { ...devices['Desktop Chrome'] }, + dependencies: ['login_serverless'], + }, + ], +}); diff --git a/x-pack/test/security_solution_playwright/tests/enable_risk_score_redirect.spec.ts b/x-pack/test/security_solution_playwright/tests/enable_risk_score_redirect.spec.ts new file mode 100644 index 0000000000000..79222975ed121 --- /dev/null +++ b/x-pack/test/security_solution_playwright/tests/enable_risk_score_redirect.spec.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { expect, test } from '@playwright/test'; +import { PageFactory } from '../page_objects/page_factory'; +import { EntityAnalyticsPage } from '../page_objects/entity_analytics_po'; +import { EntityAnalyticsManagementPage } from '../page_objects/entity_analytics_management_po'; +import { createEsArchiver } from '../fixtures/es_archiver'; + +let entityAnalyticsPage: EntityAnalyticsPage; +let entityAnalyticsManagementPage: EntityAnalyticsManagementPage; + +test.beforeAll(async () => { + const esArchiver = await createEsArchiver(); + await esArchiver.loadIfNeeded('auditbeat_single'); +}); + +test.describe('Enable risk scores from dashboard', { tag: ['@serverless', '@ess'] }, () => { + test.use({ storageState: '.auth/user.json' }); + test.beforeEach(async ({ page }) => { + entityAnalyticsPage = await PageFactory.createEntityAnalyticsPage(page); + await entityAnalyticsPage.navigates(); + }); + test('host risk enable button should redirect to entity management page', async () => { + await entityAnalyticsPage.waitForEnableHostRiskScoreToBePresent(); + entityAnalyticsManagementPage = await entityAnalyticsPage.enableHostRisk(); + + await expect(entityAnalyticsManagementPage.entityAnalyticsManagementPageTitle).toHaveText( + 'Entity Risk Score' + ); + }); + + test('user risk enable button should redirect to entity management page', async () => { + await entityAnalyticsPage.waitForEnableUserRiskScoreToBePresent(); + entityAnalyticsManagementPage = await entityAnalyticsPage.enableUserRisk(); + + await expect(entityAnalyticsManagementPage.entityAnalyticsManagementPageTitle).toHaveText( + 'Entity Risk Score' + ); + }); +}); diff --git a/x-pack/test/security_solution_playwright/tests/manual_rule_run.spec.ts b/x-pack/test/security_solution_playwright/tests/manual_rule_run.spec.ts new file mode 100644 index 0000000000000..f8effa6cd279c --- /dev/null +++ b/x-pack/test/security_solution_playwright/tests/manual_rule_run.spec.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 { expect, test } from '@playwright/test'; +import { PageFactory } from '../page_objects/page_factory'; +import { RuleDetailsPage } from '../page_objects/rule_details_page_po'; +import { createRule, deleteAllRules } from '../api_utils/rules'; +import { deleteAllSecurityDocuments } from '../api_utils/documents'; +import { RuleManagementPage } from '../page_objects/rule_management_po'; +import { createEsArchiver } from '../fixtures/es_archiver'; + +let ruleDetailsPage: RuleDetailsPage; +let ruleManagementPage: RuleManagementPage; + +test.beforeAll(async () => { + const esArchiver = await createEsArchiver(); + await esArchiver.loadIfNeeded('auditbeat_single'); +}); + +test.describe('Manual rule run', { tag: ['@ess', '@serverless'] }, () => { + test.use({ storageState: '.auth/user.json' }); + + test.beforeEach(async ({ request }) => { + await deleteAllRules(request); + await deleteAllSecurityDocuments(request); + }); + + test('schedule from rule details page', async ({ request, page }) => { + const { id: ruleId } = await createRule(request); + + ruleDetailsPage = await PageFactory.createRuleDetailsPage(page); + + await ruleDetailsPage.navigateTo(ruleId); + await ruleDetailsPage.manualRuleRun(); + + await expect(ruleDetailsPage.toaster).toHaveText( + 'Successfully scheduled manual run for 1 rule' + ); + }); + + test('schedule from rules management table', async ({ request, page }) => { + await createRule(request); + + ruleManagementPage = await PageFactory.createRuleManagementPage(page); + + await ruleManagementPage.navigate(); + await ruleManagementPage.disableAutoRefresh(); + await ruleManagementPage.manuallyRunFirstRule(); + + await expect(ruleManagementPage.toaster).toHaveText( + 'Successfully scheduled manual run for 1 rule' + ); + }); +}); diff --git a/x-pack/test/security_solution_playwright/tests/setup/login_ess.ts b/x-pack/test/security_solution_playwright/tests/setup/login_ess.ts new file mode 100644 index 0000000000000..028cc3e9c36a6 --- /dev/null +++ b/x-pack/test/security_solution_playwright/tests/setup/login_ess.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 { test } from '@playwright/test'; +import { getCommonHeaders } from '../../api_utils/headers'; + +export const authFile = '.auth/user.json'; + +test('login', { tag: '@ess' }, async ({ request }) => { + const headers = await getCommonHeaders(); + + await request.post(`${process.env.KIBANA_URL}/internal/security/login`, { + headers, + data: { + providerType: 'basic', + providerName: 'basic', + currentURL: '/', + params: { + username: process.env.ELASTICSEARCH_USERNAME, + password: process.env.ELASTICSEARCH_PASSWORD, + }, + }, + }); + + await request.storageState({ path: authFile }); +}); diff --git a/x-pack/test/security_solution_playwright/tests/setup/login_serverless.ts b/x-pack/test/security_solution_playwright/tests/setup/login_serverless.ts new file mode 100644 index 0000000000000..9f37cea0ebf8f --- /dev/null +++ b/x-pack/test/security_solution_playwright/tests/setup/login_serverless.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import fs from 'fs'; +import path from 'path'; +import { test } from '../../fixtures/saml'; + +export const authFile = '.auth/user.json'; + +test('serverless', { tag: '@serverless' }, async ({ samlSessionManager }) => { + const cookie = await samlSessionManager.getInteractiveUserSessionCookieWithRoleScope( + 'platform_engineer' + ); + const parsedUrl = new URL(process.env.KIBANA_URL!); + const domain = parsedUrl.hostname; + const maxAge = 100 * 365 * 24 * 60 * 60; + + const authData = { + cookies: [ + { + name: 'sid', + value: cookie, + expires: maxAge, + secure: false, + sameSite: 'Lax', + domain, + path: '/', + httpOnly: true, + }, + ], + }; + + fs.mkdirSync(path.dirname(authFile), { recursive: true }); + fs.writeFileSync(authFile, JSON.stringify(authData, null, 2)); +}); diff --git a/x-pack/test/security_solution_playwright/tsconfig.json b/x-pack/test/security_solution_playwright/tsconfig.json new file mode 100644 index 0000000000000..bd7a213584195 --- /dev/null +++ b/x-pack/test/security_solution_playwright/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "types": ["node"], + "outDir": "target/types" + }, + "include": ["index.d.ts"], + "kbn_references": [ + { + "path": "../../plugins/security_solution/tsconfig.json", + "force": true + }, + ], + "exclude": [ + "target/**/*" + ] +} diff --git a/x-pack/test/spaces_api_integration/common/config.ts b/x-pack/test/spaces_api_integration/common/config.ts index f1e08457f692b..f2074fac8bea1 100644 --- a/x-pack/test/spaces_api_integration/common/config.ts +++ b/x-pack/test/spaces_api_integration/common/config.ts @@ -6,7 +6,6 @@ */ import path from 'path'; -// @ts-expect-error we have to check types with "allowJs: false" for now, causing this import to fail import { REPO_ROOT } from '@kbn/repo-info'; import { FtrConfigProviderContext } from '@kbn/test'; diff --git a/yarn.lock b/yarn.lock index a43ef3ac5c8bb..4ea12b7c510fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8182,6 +8182,13 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== +"@playwright/test@=1.46.0": + version "1.46.0" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.46.0.tgz#ccea6d22c40ee7fa567e4192fafbdf2a907e2714" + integrity sha512-/QYft5VArOrGRP5pgkrfKksqsKA6CEFyGQ/gjNe6q0y4tZ1aaPfq4gIjudr1s3D+pXyrPRdsy4opKDrjBabE5w== + dependencies: + playwright "1.46.0" + "@pmmmwh/react-refresh-webpack-plugin@^0.5.3": version "0.5.7" resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.7.tgz#58f8217ba70069cc6a73f5d7e05e85b458c150e2" @@ -16382,7 +16389,7 @@ dotenv-expand@^5.1.0: resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== -dotenv@^16.0.2, dotenv@^16.0.3: +dotenv@^16.0.2, dotenv@^16.0.3, dotenv@^16.4.5: version "16.4.5" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== @@ -25349,6 +25356,13 @@ playwright-chromium@=1.38.1: dependencies: playwright-core "1.38.1" +playwright-chromium@=1.46.0: + version "1.46.0" + resolved "https://registry.yarnpkg.com/playwright-chromium/-/playwright-chromium-1.46.0.tgz#f24228fec92b380ccc8f5f365b897e9d88b612f6" + integrity sha512-UTHYZsr49XFYRQkpCfaHxL63vfu6uThxR1DrNwnU6qik/OworFcugTOJMWFMoop3QP+ThU8laAMumauLdLZXCQ== + dependencies: + playwright-core "1.46.0" + playwright-core@1.38.0: version "1.38.0" resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.38.0.tgz#cb8e135da1c0b1918b070642372040ed9aa7009a" @@ -25359,6 +25373,20 @@ playwright-core@1.38.1, playwright-core@=1.38.1: resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.38.1.tgz#75a3c470aa9576b7d7c4e274de3d79977448ba08" integrity sha512-tQqNFUKa3OfMf4b2jQ7aGLB8o9bS3bOY0yMEtldtC2+spf8QXG9zvXLTXUeRsoNuxEYMgLYR+NXfAa1rjKRcrg== +playwright-core@1.46.0: + version "1.46.0" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.46.0.tgz#2336ac453a943abf0dc95a76c117f9d3ebd390eb" + integrity sha512-9Y/d5UIwuJk8t3+lhmMSAJyNP1BUC/DqP3cQJDQQL/oWqAiuPTLgy7Q5dzglmTLwcBRdetzgNM/gni7ckfTr6A== + +playwright@1.46.0, playwright@=1.46.0: + version "1.46.0" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.46.0.tgz#c7ff490deae41fc1e814bf2cb62109dd9351164d" + integrity sha512-XYJ5WvfefWONh1uPAUAi0H2xXV5S3vrtcnXe6uAOgdGi3aSpqOSXX08IAjXW34xitfuOJsvXU5anXZxPSEQiJw== + dependencies: + playwright-core "1.46.0" + optionalDependencies: + fsevents "2.3.2" + playwright@=1.38.0: version "1.38.0" resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.38.0.tgz#0ee19d38512b7b1f961c0eb44008a6fed373d206" From f60565381a565ef9effc134296e51cf040c897c9 Mon Sep 17 00:00:00 2001 From: Achyut Jhunjhunwala Date: Fri, 6 Sep 2024 14:32:01 +0200 Subject: [PATCH 81/99] [Dataset Quality] Fix flakiness with closing flyout (#192250) ## Summary Fixes a flaky test, caused due to checking for a field post closing the Flyout on MKI Build Job - https://buildkite.com/elastic/appex-qa-serverless-kibana-ftr-tests/builds/2730 --- .../dataset_quality_details_degraded_field_flyout.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_details_degraded_field_flyout.ts b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_details_degraded_field_flyout.ts index 0f7b11fbe2972..86632ec5a4bfc 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_details_degraded_field_flyout.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_details_degraded_field_flyout.ts @@ -76,10 +76,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await PageObjects.datasetQuality.closeFlyout(); - - await testSubjects.missingOrFail( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsDegradedFieldFlyout - ); }); }); From 78081ead1db095ec984d6c4d9bcbac4effc67794 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Fri, 6 Sep 2024 08:33:18 -0400 Subject: [PATCH 82/99] Bump micromatch to version 4.0.8 (#192218) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a4bdd399676ad..8a371be7f7b82 100644 --- a/package.json +++ b/package.json @@ -1736,7 +1736,7 @@ "lmdb": "^2.9.2", "loader-utils": "^2.0.4", "marge": "^1.0.1", - "micromatch": "^4.0.7", + "micromatch": "^4.0.8", "mini-css-extract-plugin": "1.1.0", "minimist": "^1.2.6", "mocha": "^10.1.0", diff --git a/yarn.lock b/yarn.lock index 4ea12b7c510fa..c289e1912efaf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23130,10 +23130,10 @@ micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" - integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== +micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: braces "^3.0.3" picomatch "^2.3.1" From 76072882a01d0d5979cacc8e2407979d6100ec7e Mon Sep 17 00:00:00 2001 From: Sid Date: Fri, 6 Sep 2024 14:56:58 +0200 Subject: [PATCH 83/99] [Serverless][Chore] Update tests for role name validation (#192231) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow up to https://github.com/elastic/kibana/pull/191894 ### Summary Adds tests to test all cases of valid and invalid role names for serverless custom roles. #### Notes - The tests don't test for leading/trailing white spaces as that's already covered by the validator for _all_ versions of Kibana. --------- Co-authored-by: Elastic Machine Co-authored-by: “jeramysoucy” --- .../roles/edit_role/validate_role.test.ts | 131 ++++++++++-------- 1 file changed, 76 insertions(+), 55 deletions(-) diff --git a/x-pack/plugins/security/public/management/roles/edit_role/validate_role.test.ts b/x-pack/plugins/security/public/management/roles/edit_role/validate_role.test.ts index 628a9662d050c..59d1a3cfcb1a6 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/validate_role.test.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/validate_role.test.ts @@ -102,24 +102,30 @@ describe('validateRoleName for serverless', () => { beforeEach(() => { validator = new RoleValidator({ shouldValidate: true, buildFlavor: 'serverless' }); }); - test('should not allow whitespace', () => { - const role = { - name: 'role name', - elasticsearch: { - cluster: [], - indices: [], - run_as: [], - }, - kibana: [], - }; - expect(validator.validateRoleName(role)).toEqual({ - isInvalid: true, - error: `Name must contain only alphanumeric characters, and non-leading dots, hyphens, or underscores.`, + + const charList = `!#%^&*()+=[]{}\|';:"/,<>?`.split(''); + charList.forEach((element) => { + test(`it should not allow special characters ('${element}')`, () => { + const role = { + name: `role${element}name`, + elasticsearch: { + cluster: [], + indices: [], + run_as: [], + }, + kibana: [], + }; + + expect(validator.validateRoleName(role)).toEqual({ + isInvalid: true, + error: `Name must contain only alphanumeric characters, and non-leading dots, hyphens, or underscores.`, + }); }); }); - test('should not allow leading symbols', () => { + + test('should throw error for contained whitespace characters', () => { const role = { - name: '.rolename', + name: 'role name', elasticsearch: { cluster: [], indices: [], @@ -132,48 +138,63 @@ describe('validateRoleName for serverless', () => { error: `Name must contain only alphanumeric characters, and non-leading dots, hyphens, or underscores.`, }); }); - test('should allow underscores contained', () => { - const role = { - name: 'role_name', - elasticsearch: { - cluster: [], - indices: [], - run_as: [], - }, - kibana: [], - }; - expect(validator.validateRoleName(role)).toEqual({ - isInvalid: false, - }); + + test('should throw error for invalid leading characters', () => { + const invalidRoleNames = ['.rolename', '_rolename', '-rolename']; + + for (const roleName of invalidRoleNames) { + const role = { + name: roleName, + elasticsearch: { + cluster: [], + indices: [], + run_as: [], + }, + kibana: [], + }; + expect(validator.validateRoleName(role)).toEqual({ + isInvalid: true, + error: `Name must contain only alphanumeric characters, and non-leading dots, hyphens, or underscores.`, + }); + } }); - test('should allow valid names', () => { - const role = { - name: 'rolename_', - elasticsearch: { - cluster: [], - indices: [], - run_as: [], - }, - kibana: [], - }; - expect(validator.validateRoleName(role)).toEqual({ - isInvalid: false, - }); + + test('should throw error for leading and trailing whitespace characters', () => { + const invalidRoleNames = [' rolename', 'rolename ']; + + for (const roleName of invalidRoleNames) { + const role = { + name: roleName, + elasticsearch: { + cluster: [], + indices: [], + run_as: [], + }, + kibana: [], + }; + expect(validator.validateRoleName(role)).toEqual({ + isInvalid: true, + error: `Name must not contain leading or trailing spaces.`, + }); + } }); - test('should not allow any special characters except for underscore, dots and hyphens', () => { - const role = { - name: 'role+name', - elasticsearch: { - cluster: [], - indices: [], - run_as: [], - }, - kibana: [], - }; - expect(validator.validateRoleName(role)).toEqual({ - isInvalid: true, - error: `Name must contain only alphanumeric characters, and non-leading dots, hyphens, or underscores.`, - }); + + test('should allow valid names', () => { + const validRoleNames = ['rolename', 'role-name', 'role.name', 'role_name', 'role.123.role']; + for (const roleName of validRoleNames) { + const role = { + name: roleName, + elasticsearch: { + cluster: [], + indices: [], + run_as: [], + }, + kibana: [], + }; + expect(validator.validateRoleName(role)).toEqual({ + isInvalid: false, + }); + } }); }); From 335b153a92acd4a2bd8969193040260d6c557489 Mon Sep 17 00:00:00 2001 From: Ersin Erdal <92688503+ersin-erdal@users.noreply.github.com> Date: Fri, 6 Sep 2024 15:40:27 +0200 Subject: [PATCH 84/99] Mark slack rate-limiting errors as user errors (#192200) Resolves: #191082 This PR marks rate-limiting responses of the slack webhook connector as user error. ### To verify: Put the below codes[ in the try-catch block](https://github.com/elastic/kibana/blob/dfd85051cf4796777e7d45649a2bbc59d1c2f9a9/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts#L168) of the webhook connector to force it to fail. ``` const err = new Error('test'); err.original = { response: { status: 429, statusText: 'failure', headers: {} } }; throw err; ``` run Kibana and create a rule with slack webhook connector. After the first run, there must be an error on your terminal and a user error record for the .slack-webhook connector in the metrics JSON on `/api/task_manager/metrics` --- .../connector_types/slack/index.test.ts | 49 ++++++++++++++++--- .../server/connector_types/slack/index.ts | 14 ++++-- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts index 7d897ce5a3b77..b565963ce8fba 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import { IncomingWebhook } from '@slack/webhook'; import { Logger } from '@kbn/core/server'; import { Services, @@ -22,14 +22,9 @@ import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.moc import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { loggerMock } from '@kbn/logging-mocks'; +import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; -jest.mock('@slack/webhook', () => { - return { - IncomingWebhook: jest.fn().mockImplementation(() => { - return { send: (message: string) => {} }; - }), - }; -}); +const sendSpy = jest.spyOn(IncomingWebhook.prototype, 'send'); const services: Services = actionsMock.createServices(); const mockedLogger: jest.Mocked = loggerMock.create(); @@ -364,4 +359,42 @@ describe('execute()', () => { ); expect(params.message).toBe('`*bold*`'); }); + + test('returns a user error for rate-limiting responses', async () => { + const configUtils = actionsConfigMock.create(); + + configUtils.getProxySettings.mockReturnValue({ + proxyUrl: 'https://someproxyhost', + proxySSLSettings: { + verificationMode: 'none', + }, + proxyBypassHosts: undefined, + proxyOnlyHosts: undefined, + }); + + sendSpy.mockRejectedValueOnce({ + original: { response: { status: 429, statusText: 'failure', headers: {} } }, + }); + + connectorType = getConnectorType({}); + + expect( + await connectorType.executor({ + actionId: 'some-id', + services, + config: {}, + secrets: { webhookUrl: 'http://example.com' }, + params: { message: '429' }, + configurationUtilities: configUtils, + logger: mockedLogger, + connectorUsageCollector, + }) + ).toEqual({ + actionId: 'some-id', + errorSource: TaskErrorSource.USER, + message: 'error posting a slack message, retry later', + retry: true, + status: 'error', + }); + }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts index 489d7c22b0286..5ba6318f79a07 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts @@ -28,6 +28,7 @@ import { } from '@kbn/actions-plugin/common/types'; import { renderMustacheString } from '@kbn/actions-plugin/server/lib/mustache_renderer'; import { getCustomAgents } from '@kbn/actions-plugin/server/lib/get_custom_agents'; +import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { getRetryAfterIntervalFromHeaders } from '../lib/http_response_retry_header'; export type SlackConnectorType = ConnectorType< @@ -175,7 +176,7 @@ async function slackExecutor( // special handling for 5xx if (status >= 500) { - return retryResult(actionId, err.message); + return retryResult(actionId, err.message, TaskErrorSource.FRAMEWORK); } // special handling for rate limiting @@ -183,7 +184,7 @@ async function slackExecutor( return pipe( getRetryAfterIntervalFromHeaders(headers), map((retry) => retryResultSeconds(actionId, err.message, retry)), - getOrElse(() => retryResult(actionId, err.message)) + getOrElse(() => retryResult(actionId, err.message, TaskErrorSource.USER)) ); } @@ -245,7 +246,11 @@ function serviceErrorResult( }; } -function retryResult(actionId: string, message: string): ConnectorTypeExecutorResult { +function retryResult( + actionId: string, + serviceMessage: string, + errorSource: TaskErrorSource +): ConnectorTypeExecutorResult { const errMessage = i18n.translate( 'xpack.stackConnectors.slack.errorPostingRetryLaterErrorMessage', { @@ -257,6 +262,8 @@ function retryResult(actionId: string, message: string): ConnectorTypeExecutorRe message: errMessage, retry: true, actionId, + errorSource, + serviceMessage, }; } @@ -283,5 +290,6 @@ function retryResultSeconds( retry, actionId, serviceMessage: message, + errorSource: TaskErrorSource.USER, }; } From 3cc70291970838c4d8f10e55230cc2a8bfbf0564 Mon Sep 17 00:00:00 2001 From: Marshall Main <55718608+marshallmain@users.noreply.github.com> Date: Fri, 6 Sep 2024 06:41:57 -0700 Subject: [PATCH 85/99] [Security Solution] Quickstart script tooling for Detections and Response (#190634) ## Summary Creates CLI script tooling for building data, rules, exceptions, and lists in any (local, cloud, serverless) environment for manual testing. The initial commits here add generated clients for accessing security solution, exceptions, and lists APIs and a placeholder script where those clients are set up for use. See README for more details. Much of the code in this PR is auto-generated clients. The hand written code is intended to be primarily in `quickstart/modules/`, where we can add wrapper code to simplify the process for common test environment setup. For example, `createValueListException` takes an array of items and some metadata and automatically creates a new value list and an exception that references that value list. `/modules/data/` contains functions to generate documents of arbitrary size, and we can add more functions to create various other types of documents. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../src/openapi_generator.ts | 19 +- .../src/parser/get_generation_context.ts | 8 +- .../src/parser/lib/get_api_operations_list.ts | 3 + .../src/parser/openapi_types.ts | 8 + .../src/template_service/register_helpers.ts | 3 +- .../src/template_service/template_service.ts | 6 +- .../api_client_quickstart.handlebars | 75 + .../api/quickstart_client.gen.ts | 375 ++++ .../scripts/openapi_generate.js | 14 + .../tsconfig.json | 6 +- .../api/quickstart_client.gen.ts | 370 +++ .../scripts/openapi_generate.js | 14 + .../tsconfig.json | 4 + packages/kbn-securitysolution-utils/index.ts | 1 + .../src/axios/index.ts | 71 + .../src/client_concurrency/index.ts | 36 + .../src/kbn_client/kbn_client_requester.ts | 2 +- .../common/api/quickstart_client.gen.ts | 1998 +++++++++++++++++ .../scripts/openapi/generate.js | 16 + .../scripts/quickstart/README.md | 136 ++ .../scripts/quickstart/modules/data/index.ts | 54 + .../modules/entity_analytics/index.ts | 154 ++ .../quickstart/modules/exceptions/index.ts | 117 + .../scripts/quickstart/modules/lists/index.ts | 40 + .../quickstart/modules/mappings/index.ts | 86 + .../scripts/quickstart/modules/rules/index.ts | 23 + .../modules/rules/new_terms/basic_rule.ts | 64 + .../quickstart/modules/rules/query/index.ts | 17 + .../modules/rules/threat_match/index.ts | 33 + .../scripts/quickstart/modules/rules/utils.ts | 6 + .../scripts/quickstart/run.js | 9 + .../scripts/quickstart/scratchpad.ts | 98 + .../plugins/security_solution/tsconfig.json | 2 + 33 files changed, 3855 insertions(+), 13 deletions(-) create mode 100644 packages/kbn-openapi-generator/src/template_service/templates/api_client_quickstart.handlebars create mode 100644 packages/kbn-securitysolution-exceptions-common/api/quickstart_client.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/quickstart_client.gen.ts create mode 100644 packages/kbn-securitysolution-utils/src/axios/index.ts create mode 100644 packages/kbn-securitysolution-utils/src/client_concurrency/index.ts create mode 100644 x-pack/plugins/security_solution/common/api/quickstart_client.gen.ts create mode 100644 x-pack/plugins/security_solution/scripts/quickstart/README.md create mode 100644 x-pack/plugins/security_solution/scripts/quickstart/modules/data/index.ts create mode 100644 x-pack/plugins/security_solution/scripts/quickstart/modules/entity_analytics/index.ts create mode 100644 x-pack/plugins/security_solution/scripts/quickstart/modules/exceptions/index.ts create mode 100644 x-pack/plugins/security_solution/scripts/quickstart/modules/lists/index.ts create mode 100644 x-pack/plugins/security_solution/scripts/quickstart/modules/mappings/index.ts create mode 100644 x-pack/plugins/security_solution/scripts/quickstart/modules/rules/index.ts create mode 100644 x-pack/plugins/security_solution/scripts/quickstart/modules/rules/new_terms/basic_rule.ts create mode 100644 x-pack/plugins/security_solution/scripts/quickstart/modules/rules/query/index.ts create mode 100644 x-pack/plugins/security_solution/scripts/quickstart/modules/rules/threat_match/index.ts create mode 100644 x-pack/plugins/security_solution/scripts/quickstart/modules/rules/utils.ts create mode 100644 x-pack/plugins/security_solution/scripts/quickstart/run.js create mode 100644 x-pack/plugins/security_solution/scripts/quickstart/scratchpad.ts diff --git a/packages/kbn-openapi-generator/src/openapi_generator.ts b/packages/kbn-openapi-generator/src/openapi_generator.ts index b5e73613139aa..81d94e40b338c 100644 --- a/packages/kbn-openapi-generator/src/openapi_generator.ts +++ b/packages/kbn-openapi-generator/src/openapi_generator.ts @@ -19,7 +19,7 @@ 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 type { OpenApiDocument, ParsedSource } from './parser/openapi_types'; import { initTemplateService, TemplateName } from './template_service/template_service'; export interface GeneratorConfig { @@ -54,11 +54,12 @@ export const generate = async (config: GeneratorConfig) => { const schemaPaths = await globby([sourceFilesGlob]); console.log(`🕵️‍♀️ Found ${schemaPaths.length} schemas, parsing`); - let parsedSources = await Promise.all( + let parsedSources: ParsedSource[] = await Promise.all( schemaPaths.map(async (sourcePath) => { const parsedSchema = (await SwaggerParser.parse(sourcePath)) as OpenApiDocument; return { sourcePath, + generatedPath: getGeneratedFilePath(sourcePath), generationContext: getGenerationContext(parsedSchema), }; }) @@ -68,6 +69,10 @@ export const generate = async (config: GeneratorConfig) => { ({ generationContext }) => generationContext.operations.length > 0 || generationContext.components !== undefined ); + parsedSources.sort((a, b) => a.sourcePath.localeCompare(b.sourcePath)); + parsedSources.forEach((source) => + source.generationContext.operations.sort((a, b) => a.operationId.localeCompare(b.operationId)) + ); console.log(`🧹 Cleaning up any previously generated artifacts`); if (bundle) { @@ -92,26 +97,24 @@ export const generate = async (config: GeneratorConfig) => { // Sort the operations by operationId so the output is deterministic .sort((a, b) => a.operationId.localeCompare(b.operationId)); - const result = TemplateService.compileTemplate(templateName, { + const result = TemplateService.compileBundleTemplate(templateName, { operations, - components: {}, + sources: parsedSources, info: { title, version: 'Bundle (no version)', }, - imports: {}, - circularRefs: new Set(), }); await fs.writeFile(bundle.outFile, result); console.log(`📖 Wrote bundled artifact to ${chalk.bold(bundle.outFile)}`); } else { await Promise.all( - parsedSources.map(async ({ sourcePath, generationContext }) => { + parsedSources.map(async ({ generatedPath, generationContext }) => { const result = TemplateService.compileTemplate(templateName, generationContext); // Write the generation result to disk - await fs.writeFile(getGeneratedFilePath(sourcePath), result); + await fs.writeFile(generatedPath, result); }) ); } diff --git a/packages/kbn-openapi-generator/src/parser/get_generation_context.ts b/packages/kbn-openapi-generator/src/parser/get_generation_context.ts index 2813ff85201e0..b12d188b2c560 100644 --- a/packages/kbn-openapi-generator/src/parser/get_generation_context.ts +++ b/packages/kbn-openapi-generator/src/parser/get_generation_context.ts @@ -11,7 +11,7 @@ import { getApiOperationsList } from './lib/get_api_operations_list'; import { getComponents } from './lib/get_components'; import { getImportsMap, ImportsMap } from './lib/get_imports_map'; import { normalizeSchema } from './lib/normalize_schema'; -import { NormalizedOperation, OpenApiDocument } from './openapi_types'; +import { NormalizedOperation, OpenApiDocument, ParsedSource } from './openapi_types'; import { getInfo } from './lib/get_info'; import { getCircularRefs } from './lib/get_circular_refs'; @@ -23,6 +23,12 @@ export interface GenerationContext { circularRefs: Set; } +export interface BundleGenerationContext { + operations: NormalizedOperation[]; + sources: ParsedSource[]; + info: OpenAPIV3.InfoObject; +} + export function getGenerationContext(document: OpenApiDocument): GenerationContext { const normalizedDocument = normalizeSchema(document); diff --git a/packages/kbn-openapi-generator/src/parser/lib/get_api_operations_list.ts b/packages/kbn-openapi-generator/src/parser/lib/get_api_operations_list.ts index ac63820555419..f275814dbfa6a 100644 --- a/packages/kbn-openapi-generator/src/parser/lib/get_api_operations_list.ts +++ b/packages/kbn-openapi-generator/src/parser/lib/get_api_operations_list.ts @@ -88,6 +88,8 @@ export function getApiOperationsList(parsedSchema: OpenApiDocument): NormalizedO const requestBody = operation.requestBody?.content?.['application/json']?.schema as | NormalizedSchemaItem | undefined; + const requestAttachment = operation.requestBody?.content?.['multipart/form-data'] + ?.schema as NormalizedSchemaItem | undefined; const normalizedOperation: NormalizedOperation = { path, method, @@ -98,6 +100,7 @@ export function getApiOperationsList(parsedSchema: OpenApiDocument): NormalizedO requestParams, requestQuery, requestBody, + requestAttachment, response, }; diff --git a/packages/kbn-openapi-generator/src/parser/openapi_types.ts b/packages/kbn-openapi-generator/src/parser/openapi_types.ts index 669d1d9b68764..b05367a0f937d 100644 --- a/packages/kbn-openapi-generator/src/parser/openapi_types.ts +++ b/packages/kbn-openapi-generator/src/parser/openapi_types.ts @@ -7,6 +7,7 @@ */ import type { OpenAPIV3 } from 'openapi-types'; +import { GenerationContext } from './get_generation_context'; interface AdditionalProperties { /** @@ -74,5 +75,12 @@ export interface NormalizedOperation { requestParams?: NormalizedSchemaItem; requestQuery?: NormalizedSchemaItem; requestBody?: NormalizedSchemaItem; + requestAttachment?: NormalizedSchemaItem; response?: NormalizedSchemaItem; } + +export interface ParsedSource { + sourcePath: string; + generatedPath: string; + generationContext: GenerationContext; +} diff --git a/packages/kbn-openapi-generator/src/template_service/register_helpers.ts b/packages/kbn-openapi-generator/src/template_service/register_helpers.ts index 8df6d4c1fe2c2..e368d4d47120a 100644 --- a/packages/kbn-openapi-generator/src/template_service/register_helpers.ts +++ b/packages/kbn-openapi-generator/src/template_service/register_helpers.ts @@ -8,7 +8,7 @@ import type Handlebars from '@kbn/handlebars'; import { HelperOptions } from 'handlebars'; -import { snakeCase, camelCase } from 'lodash'; +import { snakeCase, camelCase, upperCase } from 'lodash'; export function registerHelpers(handlebarsInstance: typeof Handlebars) { handlebarsInstance.registerHelper('concat', (...args) => { @@ -17,6 +17,7 @@ export function registerHelpers(handlebarsInstance: typeof Handlebars) { }); handlebarsInstance.registerHelper('snakeCase', snakeCase); handlebarsInstance.registerHelper('camelCase', camelCase); + handlebarsInstance.registerHelper('upperCase', upperCase); handlebarsInstance.registerHelper('toJSON', (value: unknown) => { return JSON.stringify(value); }); diff --git a/packages/kbn-openapi-generator/src/template_service/template_service.ts b/packages/kbn-openapi-generator/src/template_service/template_service.ts index 06d8336cd7962..653147df2a5ef 100644 --- a/packages/kbn-openapi-generator/src/template_service/template_service.ts +++ b/packages/kbn-openapi-generator/src/template_service/template_service.ts @@ -8,7 +8,7 @@ import Handlebars from 'handlebars'; import { resolve } from 'path'; -import { GenerationContext } from '../parser/get_generation_context'; +import { BundleGenerationContext, GenerationContext } from '../parser/get_generation_context'; import { registerHelpers } from './register_helpers'; import { registerTemplates } from './register_templates'; @@ -18,6 +18,7 @@ export type TemplateName = (typeof AVAILABLE_TEMPLATES)[number]; export interface ITemplateService { compileTemplate: (templateName: TemplateName, context: GenerationContext) => string; + compileBundleTemplate: (templateName: TemplateName, context: BundleGenerationContext) => string; } /** @@ -34,5 +35,8 @@ export const initTemplateService = async (): Promise => { compileTemplate: (templateName: TemplateName, context: GenerationContext) => { return handlebars.compile(templates[templateName])(context); }, + compileBundleTemplate: (templateName: TemplateName, context: BundleGenerationContext) => { + return handlebars.compile(templates[templateName])(context); + }, }; }; diff --git a/packages/kbn-openapi-generator/src/template_service/templates/api_client_quickstart.handlebars b/packages/kbn-openapi-generator/src/template_service/templates/api_client_quickstart.handlebars new file mode 100644 index 0000000000000..6b9a12dc04804 --- /dev/null +++ b/packages/kbn-openapi-generator/src/template_service/templates/api_client_quickstart.handlebars @@ -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. + */ + + {{> disclaimer}} + +import type { KbnClient } from '@kbn/test'; +import { ToolingLog } from '@kbn/tooling-log'; +import { ELASTIC_HTTP_VERSION_HEADER, X_ELASTIC_INTERNAL_ORIGIN_REQUEST } from '@kbn/core-http-common'; +import { replaceParams } from '@kbn/openapi-common/shared'; +import { catchAxiosErrorFormatAndThrow } from '@kbn/securitysolution-utils'; +import { FtrProviderContext } from 'x-pack/test/api_integration/ftr_provider_context'; + +{{#each sources}} +{{#if generationContext.operations}} +import type { +{{#each generationContext.operations}} + {{operationId}}RequestQueryInput, + {{operationId}}RequestParamsInput, + {{operationId}}RequestBodyInput, + {{operationId}}Response, +{{/each}} +} from '{{generatedPath}}'; +{{/if}} +{{/each}} + +export interface ClientOptions { + kbnClient: KbnClient; + log: ToolingLog; +} + +export class Client { + readonly kbnClient: KbnClient; + readonly log: ToolingLog; + + constructor(options: ClientOptions) { + this.kbnClient = options.kbnClient; + this.log = options.log; + } +{{#each operations}} +{{#if description}} +/** + * {{{description}}} + */ +{{/if}} +async {{camelCase operationId}} ({{#if (or requestQuery requestParams requestBody requestAttachment)}}props: {{operationId}}Props{{/if}}) { + this.log.info(`${new Date().toISOString()} Calling API {{operationId}}`); + return this.kbnClient + .request{{#if response}}<{{operationId}}Response>{{/if}}({ + path: {{#if requestParams}}replaceParams('{{path}}', props.params){{else}}'{{path}}'{{/if}}, + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '{{version}}', + }, + method: '{{upperCase method}}', + {{#if requestBody}}body: props.body,{{else if requestAttachment}}body: props.attachment,{{/if}} + {{#if requestQuery}}query: props.query,{{/if}} +}) +.catch(catchAxiosErrorFormatAndThrow) +} +{{/each}} +} + +{{#each operations}} +{{#if (or requestQuery requestParams requestBody requestAttachment)}} +export interface {{operationId}}Props { + {{~#if requestQuery}}query: {{operationId}}RequestQueryInput;{{/if}} + {{~#if requestParams}}params: {{operationId}}RequestParamsInput;{{/if}} + {{~#if requestBody}}body: {{operationId}}RequestBodyInput;{{/if}} + {{~#if requestAttachment}}attachment: FormData;{{/if}} +} +{{/if}} +{{/each}} diff --git a/packages/kbn-securitysolution-exceptions-common/api/quickstart_client.gen.ts b/packages/kbn-securitysolution-exceptions-common/api/quickstart_client.gen.ts new file mode 100644 index 0000000000000..750855350011c --- /dev/null +++ b/packages/kbn-securitysolution-exceptions-common/api/quickstart_client.gen.ts @@ -0,0 +1,375 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Exceptions API client for quickstart + * version: Bundle (no version) + */ + +import type { KbnClient } from '@kbn/test'; +import { ToolingLog } from '@kbn/tooling-log'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import { replaceParams } from '@kbn/openapi-common/shared'; +import { catchAxiosErrorFormatAndThrow } from '@kbn/securitysolution-utils'; + +import type { + CreateExceptionListItemRequestBodyInput, + CreateExceptionListItemResponse, +} from './create_exception_list_item/create_exception_list_item.gen'; +import type { + CreateExceptionListRequestBodyInput, + CreateExceptionListResponse, +} from './create_exception_list/create_exception_list.gen'; +import type { + CreateRuleExceptionListItemsRequestParamsInput, + CreateRuleExceptionListItemsRequestBodyInput, + CreateRuleExceptionListItemsResponse, +} from './create_rule_exceptions/create_rule_exceptions.gen'; +import type { + CreateSharedExceptionListRequestBodyInput, + CreateSharedExceptionListResponse, +} from './create_shared_exceptions_list/create_shared_exceptions_list.gen'; +import type { + DeleteExceptionListItemRequestQueryInput, + DeleteExceptionListItemResponse, +} from './delete_exception_list_item/delete_exception_list_item.gen'; +import type { + DeleteExceptionListRequestQueryInput, + DeleteExceptionListResponse, +} from './delete_exception_list/delete_exception_list.gen'; +import type { + DuplicateExceptionListRequestQueryInput, + DuplicateExceptionListResponse, +} from './duplicate_exception_list/duplicate_exception_list.gen'; +import type { ExportExceptionListRequestQueryInput } from './export_exception_list/export_exception_list.gen'; +import type { + FindExceptionListItemsRequestQueryInput, + FindExceptionListItemsResponse, +} from './find_exception_list_items/find_exception_list_items.gen'; +import type { + FindExceptionListsRequestQueryInput, + FindExceptionListsResponse, +} from './find_exception_lists/find_exception_lists.gen'; +import type { + ImportExceptionListRequestQueryInput, + ImportExceptionListResponse, +} from './import_exceptions/import_exceptions.gen'; +import type { + ReadExceptionListItemRequestQueryInput, + ReadExceptionListItemResponse, +} from './read_exception_list_item/read_exception_list_item.gen'; +import type { + ReadExceptionListSummaryRequestQueryInput, + ReadExceptionListSummaryResponse, +} from './read_exception_list_summary/read_exception_list_summary.gen'; +import type { + ReadExceptionListRequestQueryInput, + ReadExceptionListResponse, +} from './read_exception_list/read_exception_list.gen'; +import type { + UpdateExceptionListItemRequestBodyInput, + UpdateExceptionListItemResponse, +} from './update_exception_list_item/update_exception_list_item.gen'; +import type { + UpdateExceptionListRequestBodyInput, + UpdateExceptionListResponse, +} from './update_exception_list/update_exception_list.gen'; + +export interface ClientOptions { + kbnClient: KbnClient; + log: ToolingLog; +} + +export class Client { + readonly kbnClient: KbnClient; + readonly log: ToolingLog; + + constructor(options: ClientOptions) { + this.kbnClient = options.kbnClient; + this.log = options.log; + } + async createExceptionList(props: CreateExceptionListProps) { + this.log.info(`${new Date().toISOString()} Calling API CreateExceptionList`); + return this.kbnClient + .request({ + path: '/api/exception_lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async createExceptionListItem(props: CreateExceptionListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API CreateExceptionListItem`); + return this.kbnClient + .request({ + path: '/api/exception_lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async createRuleExceptionListItems(props: CreateRuleExceptionListItemsProps) { + this.log.info(`${new Date().toISOString()} Calling API CreateRuleExceptionListItems`); + return this.kbnClient + .request({ + path: replaceParams('/api/detection_engine/rules/{id}/exceptions', props.params), + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async createSharedExceptionList(props: CreateSharedExceptionListProps) { + this.log.info(`${new Date().toISOString()} Calling API CreateSharedExceptionList`); + return this.kbnClient + .request({ + path: '/api/exceptions/shared', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async deleteExceptionList(props: DeleteExceptionListProps) { + this.log.info(`${new Date().toISOString()} Calling API DeleteExceptionList`); + return this.kbnClient + .request({ + path: '/api/exception_lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'DELETE', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async deleteExceptionListItem(props: DeleteExceptionListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API DeleteExceptionListItem`); + return this.kbnClient + .request({ + path: '/api/exception_lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'DELETE', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async duplicateExceptionList(props: DuplicateExceptionListProps) { + this.log.info(`${new Date().toISOString()} Calling API DuplicateExceptionList`); + return this.kbnClient + .request({ + path: '/api/exception_lists/_duplicate', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Exports an exception list and its associated items to an .ndjson file + */ + async exportExceptionList(props: ExportExceptionListProps) { + this.log.info(`${new Date().toISOString()} Calling API ExportExceptionList`); + return this.kbnClient + .request({ + path: '/api/exception_lists/_export', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async findExceptionListItems(props: FindExceptionListItemsProps) { + this.log.info(`${new Date().toISOString()} Calling API FindExceptionListItems`); + return this.kbnClient + .request({ + path: '/api/exception_lists/items/_find', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async findExceptionLists(props: FindExceptionListsProps) { + this.log.info(`${new Date().toISOString()} Calling API FindExceptionLists`); + return this.kbnClient + .request({ + path: '/api/exception_lists/_find', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Imports an exception list and associated items + */ + async importExceptionList(props: ImportExceptionListProps) { + this.log.info(`${new Date().toISOString()} Calling API ImportExceptionList`); + return this.kbnClient + .request({ + path: '/api/exception_lists/_import', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.attachment, + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async readExceptionList(props: ReadExceptionListProps) { + this.log.info(`${new Date().toISOString()} Calling API ReadExceptionList`); + return this.kbnClient + .request({ + path: '/api/exception_lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async readExceptionListItem(props: ReadExceptionListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API ReadExceptionListItem`); + return this.kbnClient + .request({ + path: '/api/exception_lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async readExceptionListSummary(props: ReadExceptionListSummaryProps) { + this.log.info(`${new Date().toISOString()} Calling API ReadExceptionListSummary`); + return this.kbnClient + .request({ + path: '/api/exception_lists/summary', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async updateExceptionList(props: UpdateExceptionListProps) { + this.log.info(`${new Date().toISOString()} Calling API UpdateExceptionList`); + return this.kbnClient + .request({ + path: '/api/exception_lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PUT', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async updateExceptionListItem(props: UpdateExceptionListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API UpdateExceptionListItem`); + return this.kbnClient + .request({ + path: '/api/exception_lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PUT', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } +} + +export interface CreateExceptionListProps { + body: CreateExceptionListRequestBodyInput; +} +export interface CreateExceptionListItemProps { + body: CreateExceptionListItemRequestBodyInput; +} +export interface CreateRuleExceptionListItemsProps { + params: CreateRuleExceptionListItemsRequestParamsInput; + body: CreateRuleExceptionListItemsRequestBodyInput; +} +export interface CreateSharedExceptionListProps { + body: CreateSharedExceptionListRequestBodyInput; +} +export interface DeleteExceptionListProps { + query: DeleteExceptionListRequestQueryInput; +} +export interface DeleteExceptionListItemProps { + query: DeleteExceptionListItemRequestQueryInput; +} +export interface DuplicateExceptionListProps { + query: DuplicateExceptionListRequestQueryInput; +} +export interface ExportExceptionListProps { + query: ExportExceptionListRequestQueryInput; +} +export interface FindExceptionListItemsProps { + query: FindExceptionListItemsRequestQueryInput; +} +export interface FindExceptionListsProps { + query: FindExceptionListsRequestQueryInput; +} +export interface ImportExceptionListProps { + query: ImportExceptionListRequestQueryInput; + attachment: FormData; +} +export interface ReadExceptionListProps { + query: ReadExceptionListRequestQueryInput; +} +export interface ReadExceptionListItemProps { + query: ReadExceptionListItemRequestQueryInput; +} +export interface ReadExceptionListSummaryProps { + query: ReadExceptionListSummaryRequestQueryInput; +} +export interface UpdateExceptionListProps { + body: UpdateExceptionListRequestBodyInput; +} +export interface UpdateExceptionListItemProps { + body: UpdateExceptionListItemRequestBodyInput; +} diff --git a/packages/kbn-securitysolution-exceptions-common/scripts/openapi_generate.js b/packages/kbn-securitysolution-exceptions-common/scripts/openapi_generate.js index 5fd6a9fad8876..02cb8a050ad89 100644 --- a/packages/kbn-securitysolution-exceptions-common/scripts/openapi_generate.js +++ b/packages/kbn-securitysolution-exceptions-common/scripts/openapi_generate.js @@ -34,4 +34,18 @@ const ROOT = resolve(__dirname, '..'); ), }, }); + + await generate({ + title: 'Exceptions API client for quickstart', + rootDir: ROOT, + sourceGlob: './api/**/*.schema.yaml', + templateName: 'api_client_quickstart', + skipLinting: true, + bundle: { + outFile: join( + REPO_ROOT, + 'packages/kbn-securitysolution-exceptions-common/api/quickstart_client.gen.ts' + ), + }, + }); })(); diff --git a/packages/kbn-securitysolution-exceptions-common/tsconfig.json b/packages/kbn-securitysolution-exceptions-common/tsconfig.json index a51728703b383..a58753f53a4fb 100644 --- a/packages/kbn-securitysolution-exceptions-common/tsconfig.json +++ b/packages/kbn-securitysolution-exceptions-common/tsconfig.json @@ -10,6 +10,10 @@ "@kbn/openapi-common", "@kbn/zod-helpers", "@kbn/securitysolution-lists-common", - "@kbn/zod" + "@kbn/test", + "@kbn/tooling-log", + "@kbn/core-http-common", + "@kbn/securitysolution-utils", + "@kbn/zod", ] } diff --git a/packages/kbn-securitysolution-lists-common/api/quickstart_client.gen.ts b/packages/kbn-securitysolution-lists-common/api/quickstart_client.gen.ts new file mode 100644 index 0000000000000..0e3a965ae41ff --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/quickstart_client.gen.ts @@ -0,0 +1,370 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Lists API client for quickstart + * version: Bundle (no version) + */ + +import type { KbnClient } from '@kbn/test'; +import { ToolingLog } from '@kbn/tooling-log'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import { catchAxiosErrorFormatAndThrow } from '@kbn/securitysolution-utils'; + +import type { CreateListIndexResponse } from './create_list_index/create_list_index.gen'; +import type { + CreateListItemRequestBodyInput, + CreateListItemResponse, +} from './create_list_item/create_list_item.gen'; +import type { CreateListRequestBodyInput, CreateListResponse } from './create_list/create_list.gen'; +import type { DeleteListIndexResponse } from './delete_list_index/delete_list_index.gen'; +import type { + DeleteListItemRequestQueryInput, + DeleteListItemResponse, +} from './delete_list_item/delete_list_item.gen'; +import type { + DeleteListRequestQueryInput, + DeleteListResponse, +} from './delete_list/delete_list.gen'; +import type { ExportListItemsRequestQueryInput } from './export_list_items/export_list_items.gen'; +import type { + FindListItemsRequestQueryInput, + FindListItemsResponse, +} from './find_list_items/find_list_items.gen'; +import type { FindListsRequestQueryInput, FindListsResponse } from './find_lists/find_lists.gen'; +import type { + ImportListItemsRequestQueryInput, + ImportListItemsResponse, +} from './import_list_items/import_list_items.gen'; +import type { + PatchListItemRequestBodyInput, + PatchListItemResponse, +} from './patch_list_item/patch_list_item.gen'; +import type { PatchListRequestBodyInput, PatchListResponse } from './patch_list/patch_list.gen'; +import type { ReadListIndexResponse } from './read_list_index/read_list_index.gen'; +import type { + ReadListItemRequestQueryInput, + ReadListItemResponse, +} from './read_list_item/read_list_item.gen'; +import type { ReadListPrivilegesResponse } from './read_list_privileges/read_list_privileges.gen'; +import type { ReadListRequestQueryInput, ReadListResponse } from './read_list/read_list.gen'; +import type { + UpdateListItemRequestBodyInput, + UpdateListItemResponse, +} from './update_list_item/update_list_item.gen'; +import type { UpdateListRequestBodyInput, UpdateListResponse } from './update_list/update_list.gen'; + +export interface ClientOptions { + kbnClient: KbnClient; + log: ToolingLog; +} + +export class Client { + readonly kbnClient: KbnClient; + readonly log: ToolingLog; + + constructor(options: ClientOptions) { + this.kbnClient = options.kbnClient; + this.log = options.log; + } + async createList(props: CreateListProps) { + this.log.info(`${new Date().toISOString()} Calling API CreateList`); + return this.kbnClient + .request({ + path: '/api/lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async createListIndex() { + this.log.info(`${new Date().toISOString()} Calling API CreateListIndex`); + return this.kbnClient + .request({ + path: '/api/lists/index', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async createListItem(props: CreateListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API CreateListItem`); + return this.kbnClient + .request({ + path: '/api/lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async deleteList(props: DeleteListProps) { + this.log.info(`${new Date().toISOString()} Calling API DeleteList`); + return this.kbnClient + .request({ + path: '/api/lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'DELETE', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async deleteListIndex() { + this.log.info(`${new Date().toISOString()} Calling API DeleteListIndex`); + return this.kbnClient + .request({ + path: '/api/lists/index', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'DELETE', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async deleteListItem(props: DeleteListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API DeleteListItem`); + return this.kbnClient + .request({ + path: '/api/lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'DELETE', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Exports list item values from the specified list + */ + async exportListItems(props: ExportListItemsProps) { + this.log.info(`${new Date().toISOString()} Calling API ExportListItems`); + return this.kbnClient + .request({ + path: '/api/lists/items/_export', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async findListItems(props: FindListItemsProps) { + this.log.info(`${new Date().toISOString()} Calling API FindListItems`); + return this.kbnClient + .request({ + path: '/api/lists/items/_find', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async findLists(props: FindListsProps) { + this.log.info(`${new Date().toISOString()} Calling API FindLists`); + return this.kbnClient + .request({ + path: '/api/lists/_find', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Imports a list of items from a `.txt` or `.csv` file. The maximum file size is 9 million bytes. + +You can import items to a new or existing list. + + */ + async importListItems(props: ImportListItemsProps) { + this.log.info(`${new Date().toISOString()} Calling API ImportListItems`); + return this.kbnClient + .request({ + path: '/api/lists/items/_import', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.attachment, + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async patchList(props: PatchListProps) { + this.log.info(`${new Date().toISOString()} Calling API PatchList`); + return this.kbnClient + .request({ + path: '/api/lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PATCH', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async patchListItem(props: PatchListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API PatchListItem`); + return this.kbnClient + .request({ + path: '/api/lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PATCH', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async readList(props: ReadListProps) { + this.log.info(`${new Date().toISOString()} Calling API ReadList`); + return this.kbnClient + .request({ + path: '/api/lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async readListIndex() { + this.log.info(`${new Date().toISOString()} Calling API ReadListIndex`); + return this.kbnClient + .request({ + path: '/api/lists/index', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async readListItem(props: ReadListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API ReadListItem`); + return this.kbnClient + .request({ + path: '/api/lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async readListPrivileges() { + this.log.info(`${new Date().toISOString()} Calling API ReadListPrivileges`); + return this.kbnClient + .request({ + path: '/api/lists/privileges', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async updateList(props: UpdateListProps) { + this.log.info(`${new Date().toISOString()} Calling API UpdateList`); + return this.kbnClient + .request({ + path: '/api/lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PUT', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async updateListItem(props: UpdateListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API UpdateListItem`); + return this.kbnClient + .request({ + path: '/api/lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PUT', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } +} + +export interface CreateListProps { + body: CreateListRequestBodyInput; +} +export interface CreateListItemProps { + body: CreateListItemRequestBodyInput; +} +export interface DeleteListProps { + query: DeleteListRequestQueryInput; +} +export interface DeleteListItemProps { + query: DeleteListItemRequestQueryInput; +} +export interface ExportListItemsProps { + query: ExportListItemsRequestQueryInput; +} +export interface FindListItemsProps { + query: FindListItemsRequestQueryInput; +} +export interface FindListsProps { + query: FindListsRequestQueryInput; +} +export interface ImportListItemsProps { + query: ImportListItemsRequestQueryInput; + attachment: FormData; +} +export interface PatchListProps { + body: PatchListRequestBodyInput; +} +export interface PatchListItemProps { + body: PatchListItemRequestBodyInput; +} +export interface ReadListProps { + query: ReadListRequestQueryInput; +} +export interface ReadListItemProps { + query: ReadListItemRequestQueryInput; +} +export interface UpdateListProps { + body: UpdateListRequestBodyInput; +} +export interface UpdateListItemProps { + body: UpdateListItemRequestBodyInput; +} diff --git a/packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js b/packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js index aba406bb16b4b..35bb66055c095 100644 --- a/packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js +++ b/packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js @@ -34,4 +34,18 @@ const ROOT = resolve(__dirname, '..'); ), }, }); + + await generate({ + title: 'Lists API client for quickstart', + rootDir: ROOT, + sourceGlob: './api/**/*.schema.yaml', + templateName: 'api_client_quickstart', + skipLinting: true, + bundle: { + outFile: join( + REPO_ROOT, + 'packages/kbn-securitysolution-lists-common/api/quickstart_client.gen.ts' + ), + }, + }); })(); diff --git a/packages/kbn-securitysolution-lists-common/tsconfig.json b/packages/kbn-securitysolution-lists-common/tsconfig.json index 59070e0a49731..e8149be083552 100644 --- a/packages/kbn-securitysolution-lists-common/tsconfig.json +++ b/packages/kbn-securitysolution-lists-common/tsconfig.json @@ -9,6 +9,10 @@ "kbn_references": [ "@kbn/zod-helpers", "@kbn/openapi-common", + "@kbn/test", + "@kbn/tooling-log", + "@kbn/core-http-common", + "@kbn/securitysolution-utils", "@kbn/zod", ] } diff --git a/packages/kbn-securitysolution-utils/index.ts b/packages/kbn-securitysolution-utils/index.ts index b39207bdd1902..f61e12878874a 100644 --- a/packages/kbn-securitysolution-utils/index.ts +++ b/packages/kbn-securitysolution-utils/index.ts @@ -7,6 +7,7 @@ */ export * from './src/add_remove_id_to_item'; +export * from './src/axios'; export * from './src/transform_data_to_ndjson'; export * from './src/path_validations'; export * from './src/esql'; diff --git a/packages/kbn-securitysolution-utils/src/axios/index.ts b/packages/kbn-securitysolution-utils/src/axios/index.ts new file mode 100644 index 0000000000000..cfbef31cd39dc --- /dev/null +++ b/packages/kbn-securitysolution-utils/src/axios/index.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { AxiosError } from 'axios'; + +export class FormattedAxiosError extends Error { + public readonly request: { + method: string; + url: string; + data: unknown; + }; + public readonly response: { + status: number; + statusText: string; + data: any; + }; + + constructor(axiosError: AxiosError) { + const method = axiosError.config?.method ?? ''; + const url = axiosError.config?.url ?? ''; + + super( + `${axiosError.message}${ + axiosError?.response?.data ? `: ${JSON.stringify(axiosError?.response?.data)}` : '' + }${url ? `\n(Request: ${method} ${url})` : ''}` + ); + + this.request = { + method, + url, + data: axiosError.config?.data ?? '', + }; + + this.response = { + status: axiosError?.response?.status ?? 0, + statusText: axiosError?.response?.statusText ?? '', + data: axiosError?.response?.data, + }; + + this.name = this.constructor.name; + } + + toJSON() { + return { + message: this.message, + request: this.request, + response: this.response, + }; + } + + toString() { + return JSON.stringify(this.toJSON(), null, 2); + } +} + +/** + * Used with `promise.catch()`, it will format the Axios error to a new error and will re-throw + * @param error + */ +export const catchAxiosErrorFormatAndThrow = (error: Error): never => { + if (error instanceof AxiosError) { + throw new FormattedAxiosError(error); + } + + throw error; +}; diff --git a/packages/kbn-securitysolution-utils/src/client_concurrency/index.ts b/packages/kbn-securitysolution-utils/src/client_concurrency/index.ts new file mode 100644 index 0000000000000..26a58c480c65c --- /dev/null +++ b/packages/kbn-securitysolution-utils/src/client_concurrency/index.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import limit from 'p-limit'; + +/** + * This type is just an async function's type + */ +type RequestFactory = () => Promise; + +/** + * Helper function to call a large number of async functions with limited concurrency. + * Example pattern of how to create functions to pass in: + * + * const ruleCopies = duplicateRuleParams(basicRule, 200); + * const functions = ruleCopies.map((rule) => () => detectionsClient.createRule({ body: rule })); + * + * Note that the `map` call in the example returns a *function* that calls detectionsClient.createRule, it doesn't call createRule immediately. + * + * @param functions Async functions to call with limited concurrency + * @param concurrency Maximum number of concurrent function calls + * @returns Results from all functions passed in + */ +export const concurrentlyExec = async ( + requestFactories: Array>, + concurrency: number = 10 +) => { + const limiter = limit(concurrency); + const promises = requestFactories.map((f) => limiter(f)); + return Promise.all(promises); +}; diff --git a/packages/kbn-test/src/kbn_client/kbn_client_requester.ts b/packages/kbn-test/src/kbn_client/kbn_client_requester.ts index 14489a2fef5e0..6f264da1f7264 100644 --- a/packages/kbn-test/src/kbn_client/kbn_client_requester.ts +++ b/packages/kbn-test/src/kbn_client/kbn_client_requester.ts @@ -68,7 +68,7 @@ export interface ReqOptions { description?: string; path: string; query?: Record; - method: 'GET' | 'POST' | 'PUT' | 'DELETE'; + method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; body?: any; retries?: number; headers?: Record; diff --git a/x-pack/plugins/security_solution/common/api/quickstart_client.gen.ts b/x-pack/plugins/security_solution/common/api/quickstart_client.gen.ts new file mode 100644 index 0000000000000..edd0bfe89fc8c --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/quickstart_client.gen.ts @@ -0,0 +1,1998 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: API client for quickstart + * version: Bundle (no version) + */ + +import type { KbnClient } from '@kbn/test'; +import type { ToolingLog } from '@kbn/tooling-log'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import { replaceParams } from '@kbn/openapi-common/shared'; +import { catchAxiosErrorFormatAndThrow } from '@kbn/securitysolution-utils'; + +import type { SetAlertAssigneesRequestBodyInput } from './detection_engine/alert_assignees/set_alert_assignees_route.gen'; +import type { + SetAlertTagsRequestBodyInput, + SetAlertTagsResponse, +} from './detection_engine/alert_tags/set_alert_tags/set_alert_tags.gen'; +import type { CreateAlertsIndexResponse } from './detection_engine/index_management/create_index/create_index.gen'; +import type { DeleteAlertsIndexResponse } from './detection_engine/index_management/delete_index/delete_index.gen'; +import type { ReadAlertsIndexResponse } from './detection_engine/index_management/read_index/read_index.gen'; +import type { ReadPrivilegesResponse } from './detection_engine/index_management/read_privileges/read_privileges.gen'; +import type { BootstrapPrebuiltRulesResponse } from './detection_engine/prebuilt_rules/bootstrap_prebuilt_rules/bootstrap_prebuilt_rules.gen'; +import type { InstallPrebuiltRulesAndTimelinesResponse } from './detection_engine/prebuilt_rules/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.gen'; +import type { ReadPrebuiltRulesAndTimelinesStatusResponse } from './detection_engine/prebuilt_rules/read_prebuilt_rules_and_timelines_status/read_prebuilt_rules_and_timelines_status_route.gen'; +import type { + PerformRulesBulkActionRequestQueryInput, + PerformRulesBulkActionRequestBodyInput, + PerformRulesBulkActionResponse, +} from './detection_engine/rule_management/bulk_actions/bulk_actions_route.gen'; +import type { + BulkCreateRulesRequestBodyInput, + BulkCreateRulesResponse, +} from './detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.gen'; +import type { + BulkDeleteRulesRequestBodyInput, + BulkDeleteRulesResponse, + BulkDeleteRulesPostRequestBodyInput, + BulkDeleteRulesPostResponse, +} from './detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.gen'; +import type { + BulkPatchRulesRequestBodyInput, + BulkPatchRulesResponse, +} from './detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.gen'; +import type { + BulkUpdateRulesRequestBodyInput, + BulkUpdateRulesResponse, +} from './detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.gen'; +import type { + CreateRuleRequestBodyInput, + CreateRuleResponse, +} from './detection_engine/rule_management/crud/create_rule/create_rule_route.gen'; +import type { + DeleteRuleRequestQueryInput, + DeleteRuleResponse, +} from './detection_engine/rule_management/crud/delete_rule/delete_rule_route.gen'; +import type { + PatchRuleRequestBodyInput, + PatchRuleResponse, +} from './detection_engine/rule_management/crud/patch_rule/patch_rule_route.gen'; +import type { + ReadRuleRequestQueryInput, + ReadRuleResponse, +} from './detection_engine/rule_management/crud/read_rule/read_rule_route.gen'; +import type { + UpdateRuleRequestBodyInput, + UpdateRuleResponse, +} from './detection_engine/rule_management/crud/update_rule/update_rule_route.gen'; +import type { + ExportRulesRequestQueryInput, + ExportRulesRequestBodyInput, +} from './detection_engine/rule_management/export_rules/export_rules_route.gen'; +import type { + FindRulesRequestQueryInput, + FindRulesResponse, +} from './detection_engine/rule_management/find_rules/find_rules_route.gen'; +import type { + ImportRulesRequestQueryInput, + ImportRulesResponse, +} from './detection_engine/rule_management/import_rules/import_rules_route.gen'; +import type { ReadTagsResponse } from './detection_engine/rule_management/read_tags/read_tags_route.gen'; +import type { + GetRuleExecutionEventsRequestQueryInput, + GetRuleExecutionEventsRequestParamsInput, + GetRuleExecutionEventsResponse, +} from './detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.gen'; +import type { + GetRuleExecutionResultsRequestQueryInput, + GetRuleExecutionResultsRequestParamsInput, + GetRuleExecutionResultsResponse, +} from './detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.gen'; +import type { + RulePreviewRequestBodyInput, + RulePreviewResponse, +} from './detection_engine/rule_preview/rule_preview.gen'; +import type { + CreateAlertsMigrationRequestBodyInput, + CreateAlertsMigrationResponse, +} from './detection_engine/signals_migration/create_signals_migration/create_signals_migration.gen'; +import type { + AlertsMigrationCleanupRequestBodyInput, + AlertsMigrationCleanupResponse, +} from './detection_engine/signals_migration/delete_signals_migration/delete_signals_migration.gen'; +import type { + FinalizeAlertsMigrationRequestBodyInput, + FinalizeAlertsMigrationResponse, +} from './detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration.gen'; +import type { + ReadAlertsMigrationStatusRequestQueryInput, + ReadAlertsMigrationStatusResponse, +} from './detection_engine/signals_migration/read_signals_migration_status/read_signals_migration_status.gen'; +import type { + SearchAlertsRequestBodyInput, + SearchAlertsResponse, +} from './detection_engine/signals/query_signals/query_signals_route.gen'; +import type { + SetAlertsStatusRequestBodyInput, + SetAlertsStatusResponse, +} from './detection_engine/signals/set_signal_status/set_signals_status_route.gen'; +import type { SuggestUserProfilesRequestQueryInput } from './detection_engine/users/suggest_user_profiles_route.gen'; +import type { + EndpointGetActionsDetailsRequestParamsInput, + EndpointGetActionsDetailsResponse, +} from './endpoint/actions/details/details.gen'; +import type { + EndpointFileDownloadRequestParamsInput, + EndpointFileDownloadResponse, +} from './endpoint/actions/file_download/file_download.gen'; +import type { + EndpointFileInfoRequestParamsInput, + EndpointFileInfoResponse, +} from './endpoint/actions/file_info/file_info.gen'; +import type { + EndpointGetActionsListRequestQueryInput, + EndpointGetActionsListResponse, +} from './endpoint/actions/list/list.gen'; +import type { + EndpointExecuteActionRequestBodyInput, + EndpointExecuteActionResponse, +} from './endpoint/actions/response_actions/execute/execute.gen'; +import type { + EndpointGetFileActionRequestBodyInput, + EndpointGetFileActionResponse, +} from './endpoint/actions/response_actions/get_file/get_file.gen'; +import type { + EndpointIsolateRedirectRequestBodyInput, + EndpointIsolateRedirectResponse, +} from './endpoint/actions/response_actions/isolate/deprecated_isolate.gen'; +import type { + EndpointIsolateActionRequestBodyInput, + EndpointIsolateActionResponse, +} from './endpoint/actions/response_actions/isolate/isolate.gen'; +import type { + EndpointKillProcessActionRequestBodyInput, + EndpointKillProcessActionResponse, +} from './endpoint/actions/response_actions/kill_process/kill_process.gen'; +import type { + EndpointGetProcessesActionRequestBodyInput, + EndpointGetProcessesActionResponse, +} from './endpoint/actions/response_actions/running_procs/running_procs.gen'; +import type { + EndpointScanActionRequestBodyInput, + EndpointScanActionResponse, +} from './endpoint/actions/response_actions/scan/scan.gen'; +import type { + EndpointSuspendProcessActionRequestBodyInput, + EndpointSuspendProcessActionResponse, +} from './endpoint/actions/response_actions/suspend_process/suspend_process.gen'; +import type { + EndpointUnisolateRedirectRequestBodyInput, + EndpointUnisolateRedirectResponse, +} from './endpoint/actions/response_actions/unisolate/deprecated_unisolate.gen'; +import type { + EndpointUnisolateActionRequestBodyInput, + EndpointUnisolateActionResponse, +} from './endpoint/actions/response_actions/unisolate/unisolate.gen'; +import type { + EndpointUploadActionRequestBodyInput, + EndpointUploadActionResponse, +} from './endpoint/actions/response_actions/upload/upload.gen'; +import type { EndpointGetActionsStateResponse } from './endpoint/actions/state/state.gen'; +import type { + EndpointGetActionsStatusRequestQueryInput, + EndpointGetActionsStatusResponse, +} from './endpoint/actions/status/status.gen'; +import type { + GetEndpointMetadataListRequestQueryInput, + GetEndpointMetadataListResponse, +} from './endpoint/metadata/get_metadata.gen'; +import type { + GetAgentPolicySummaryRequestQueryInput, + GetAgentPolicySummaryResponse, +} from './endpoint/policy/deprecated_agent_policy_summary.gen'; +import type { + GetPolicyResponseRequestQueryInput, + GetPolicyResponseResponse, +} from './endpoint/policy/policy_response.gen'; +import type { + CreateUpdateProtectionUpdatesNoteRequestParamsInput, + CreateUpdateProtectionUpdatesNoteRequestBodyInput, + CreateUpdateProtectionUpdatesNoteResponse, + GetProtectionUpdatesNoteRequestParamsInput, + GetProtectionUpdatesNoteResponse, +} from './endpoint/protection_updates_note/protection_updates_note.gen'; +import type { + GetEndpointSuggestionsRequestParamsInput, + GetEndpointSuggestionsRequestBodyInput, + GetEndpointSuggestionsResponse, +} from './endpoint/suggestions/get_suggestions.gen'; +import type { + BulkUpsertAssetCriticalityRecordsRequestBodyInput, + BulkUpsertAssetCriticalityRecordsResponse, +} from './entity_analytics/asset_criticality/bulk_upload_asset_criticality.gen'; +import type { + CreateAssetCriticalityRecordRequestBodyInput, + CreateAssetCriticalityRecordResponse, +} from './entity_analytics/asset_criticality/create_asset_criticality.gen'; +import type { + DeleteAssetCriticalityRecordRequestQueryInput, + DeleteAssetCriticalityRecordResponse, +} from './entity_analytics/asset_criticality/delete_asset_criticality.gen'; +import type { AssetCriticalityGetPrivilegesResponse } from './entity_analytics/asset_criticality/get_asset_criticality_privileges.gen'; +import type { GetAssetCriticalityStatusResponse } from './entity_analytics/asset_criticality/get_asset_criticality_status.gen'; +import type { + GetAssetCriticalityRecordRequestQueryInput, + GetAssetCriticalityRecordResponse, +} from './entity_analytics/asset_criticality/get_asset_criticality.gen'; +import type { + FindAssetCriticalityRecordsRequestQueryInput, + FindAssetCriticalityRecordsResponse, +} from './entity_analytics/asset_criticality/list_asset_criticality.gen'; +import type { + InternalUploadAssetCriticalityRecordsResponse, + UploadAssetCriticalityRecordsResponse, +} from './entity_analytics/asset_criticality/upload_asset_criticality_csv.gen'; +import type { DisableRiskEngineResponse } from './entity_analytics/risk_engine/engine_disable_route.gen'; +import type { EnableRiskEngineResponse } from './entity_analytics/risk_engine/engine_enable_route.gen'; +import type { InitRiskEngineResponse } from './entity_analytics/risk_engine/engine_init_route.gen'; +import type { ScheduleRiskEngineNowResponse } from './entity_analytics/risk_engine/engine_schedule_now_route.gen'; +import type { ReadRiskEngineSettingsResponse } from './entity_analytics/risk_engine/engine_settings_route.gen'; +import type { GetRiskEngineStatusResponse } from './entity_analytics/risk_engine/engine_status_route.gen'; +import type { + DeprecatedTriggerRiskScoreCalculationRequestBodyInput, + DeprecatedTriggerRiskScoreCalculationResponse, + TriggerRiskScoreCalculationRequestBodyInput, + TriggerRiskScoreCalculationResponse, +} from './entity_analytics/risk_engine/entity_calculation_route.gen'; +import type { RiskEngineGetPrivilegesResponse } from './entity_analytics/risk_engine/get_risk_engine_privileges.gen'; +import type { + PreviewRiskScoreRequestBodyInput, + PreviewRiskScoreResponse, +} from './entity_analytics/risk_engine/preview_route.gen'; +import type { + CleanDraftTimelinesRequestBodyInput, + CleanDraftTimelinesResponse, +} from './timeline/clean_draft_timelines/clean_draft_timelines_route.gen'; +import type { + CreateTimelinesRequestBodyInput, + CreateTimelinesResponse, +} from './timeline/create_timelines/create_timelines_route.gen'; +import type { + DeleteNoteRequestBodyInput, + DeleteNoteResponse, +} from './timeline/delete_note/delete_note_route.gen'; +import type { + DeleteTimelinesRequestBodyInput, + DeleteTimelinesResponse, +} from './timeline/delete_timelines/delete_timelines_route.gen'; +import type { + ExportTimelinesRequestQueryInput, + ExportTimelinesRequestBodyInput, +} from './timeline/export_timelines/export_timelines_route.gen'; +import type { + GetDraftTimelinesRequestQueryInput, + GetDraftTimelinesResponse, +} from './timeline/get_draft_timelines/get_draft_timelines_route.gen'; +import type { GetNotesRequestQueryInput } from './timeline/get_notes/get_notes_route.gen'; +import type { + GetTimelineRequestQueryInput, + GetTimelineResponse, +} from './timeline/get_timeline/get_timeline_route.gen'; +import type { + GetTimelinesRequestQueryInput, + GetTimelinesResponse, +} from './timeline/get_timelines/get_timelines_route.gen'; +import type { + ImportTimelinesRequestBodyInput, + ImportTimelinesResponse, +} from './timeline/import_timelines/import_timelines_route.gen'; +import type { + InstallPrepackedTimelinesRequestBodyInput, + InstallPrepackedTimelinesResponse, +} from './timeline/install_prepackaged_timelines/install_prepackaged_timelines_route.gen'; +import type { + PatchTimelineRequestBodyInput, + PatchTimelineResponse, +} from './timeline/patch_timelines/patch_timeline_route.gen'; +import type { + PersistFavoriteRouteRequestBodyInput, + PersistFavoriteRouteResponse, +} from './timeline/persist_favorite/persist_favorite_route.gen'; +import type { + PersistNoteRouteRequestBodyInput, + PersistNoteRouteResponse, +} from './timeline/persist_note/persist_note_route.gen'; +import type { + PersistPinnedEventRouteRequestBodyInput, + PersistPinnedEventRouteResponse, +} from './timeline/pinned_events/pinned_events_route.gen'; +import type { + ResolveTimelineRequestQueryInput, + ResolveTimelineResponse, +} from './timeline/resolve_timeline/resolve_timeline_route.gen'; + +export interface ClientOptions { + kbnClient: KbnClient; + log: ToolingLog; +} + +export class Client { + readonly kbnClient: KbnClient; + readonly log: ToolingLog; + + constructor(options: ClientOptions) { + this.kbnClient = options.kbnClient; + this.log = options.log; + } + /** + * Migrations favor data integrity over shard size. Consequently, unused or orphaned indices are artifacts of +the migration process. A successful migration will result in both the old and new indices being present. +As such, the old, orphaned index can (and likely should) be deleted. + +While you can delete these indices manually, +the endpoint accomplishes this task by applying a deletion policy to the relevant index, causing it to be deleted +after 30 days. It also deletes other artifacts specific to the migration implementation. + + */ + async alertsMigrationCleanup(props: AlertsMigrationCleanupProps) { + this.log.info(`${new Date().toISOString()} Calling API AlertsMigrationCleanup`); + return this.kbnClient + .request({ + path: '/api/detection_engine/signals/migration', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'DELETE', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async assetCriticalityGetPrivileges() { + this.log.info(`${new Date().toISOString()} Calling API AssetCriticalityGetPrivileges`); + return this.kbnClient + .request({ + path: '/internal/asset_criticality/privileges', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Ensures that the packages needed for prebuilt detection rules to work are installed and up to date + */ + async bootstrapPrebuiltRules() { + this.log.info(`${new Date().toISOString()} Calling API BootstrapPrebuiltRules`); + return this.kbnClient + .request({ + path: '/internal/detection_engine/prebuilt_rules/_bootstrap', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'POST', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Create new detection rules in bulk. + */ + async bulkCreateRules(props: BulkCreateRulesProps) { + this.log.info(`${new Date().toISOString()} Calling API BulkCreateRules`); + return this.kbnClient + .request({ + path: '/api/detection_engine/rules/_bulk_create', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Delete detection rules in bulk. + */ + async bulkDeleteRules(props: BulkDeleteRulesProps) { + this.log.info(`${new Date().toISOString()} Calling API BulkDeleteRules`); + return this.kbnClient + .request({ + path: '/api/detection_engine/rules/_bulk_delete', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'DELETE', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Deletes multiple rules. + */ + async bulkDeleteRulesPost(props: BulkDeleteRulesPostProps) { + this.log.info(`${new Date().toISOString()} Calling API BulkDeleteRulesPost`); + return this.kbnClient + .request({ + path: '/api/detection_engine/rules/_bulk_delete', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Update specific fields of existing detection rules using the `rule_id` or `id` field. + */ + async bulkPatchRules(props: BulkPatchRulesProps) { + this.log.info(`${new Date().toISOString()} Calling API BulkPatchRules`); + return this.kbnClient + .request({ + path: '/api/detection_engine/rules/_bulk_update', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PATCH', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Update multiple detection rules using the `rule_id` or `id` field. The original rules are replaced, and all unspecified fields are deleted. +> info +> You cannot modify the `id` or `rule_id` values. + + */ + async bulkUpdateRules(props: BulkUpdateRulesProps) { + this.log.info(`${new Date().toISOString()} Calling API BulkUpdateRules`); + return this.kbnClient + .request({ + path: '/api/detection_engine/rules/_bulk_update', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PUT', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Bulk upsert up to 1000 asset criticality records, creating or updating them as needed. + */ + async bulkUpsertAssetCriticalityRecords(props: BulkUpsertAssetCriticalityRecordsProps) { + this.log.info(`${new Date().toISOString()} Calling API BulkUpsertAssetCriticalityRecords`); + return this.kbnClient + .request({ + path: '/api/asset_criticality/bulk', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Retrieves a clean draft timeline. If a draft timeline does not exist, it is created and returned. + + */ + async cleanDraftTimelines(props: CleanDraftTimelinesProps) { + this.log.info(`${new Date().toISOString()} Calling API CleanDraftTimelines`); + return this.kbnClient + .request({ + path: '/api/timeline/_draft', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async createAlertsIndex() { + this.log.info(`${new Date().toISOString()} Calling API CreateAlertsIndex`); + return this.kbnClient + .request({ + path: '/api/detection_engine/index', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Initiate a migration of detection alerts. +Migrations are initiated per index. While the process is neither destructive nor interferes with existing data, it may be resource-intensive. As such, it is recommended that you plan your migrations accordingly. + + */ + async createAlertsMigration(props: CreateAlertsMigrationProps) { + this.log.info(`${new Date().toISOString()} Calling API CreateAlertsMigration`); + return this.kbnClient + .request({ + path: '/api/detection_engine/signals/migration', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Create or update a criticality record for a specific asset. + */ + async createAssetCriticalityRecord(props: CreateAssetCriticalityRecordProps) { + this.log.info(`${new Date().toISOString()} Calling API CreateAssetCriticalityRecord`); + return this.kbnClient + .request({ + path: '/api/asset_criticality', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Create a new detection rule. + */ + async createRule(props: CreateRuleProps) { + this.log.info(`${new Date().toISOString()} Calling API CreateRule`); + return this.kbnClient + .request({ + path: '/api/detection_engine/rules', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async createTimelines(props: CreateTimelinesProps) { + this.log.info(`${new Date().toISOString()} Calling API CreateTimelines`); + return this.kbnClient + .request({ + path: '/api/timeline', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async createUpdateProtectionUpdatesNote(props: CreateUpdateProtectionUpdatesNoteProps) { + this.log.info(`${new Date().toISOString()} Calling API CreateUpdateProtectionUpdatesNote`); + return this.kbnClient + .request({ + path: replaceParams( + '/api/endpoint/protection_updates_note/{package_policy_id}', + props.params + ), + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async deleteAlertsIndex() { + this.log.info(`${new Date().toISOString()} Calling API DeleteAlertsIndex`); + return this.kbnClient + .request({ + path: '/api/detection_engine/index', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'DELETE', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Delete the asset criticality record for a specific asset if it exists. + */ + async deleteAssetCriticalityRecord(props: DeleteAssetCriticalityRecordProps) { + this.log.info(`${new Date().toISOString()} Calling API DeleteAssetCriticalityRecord`); + return this.kbnClient + .request({ + path: '/api/asset_criticality', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'DELETE', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async deleteNote(props: DeleteNoteProps) { + this.log.info(`${new Date().toISOString()} Calling API DeleteNote`); + return this.kbnClient + .request({ + path: '/api/note', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'DELETE', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Delete a detection rule using the `rule_id` or `id` field. + */ + async deleteRule(props: DeleteRuleProps) { + this.log.info(`${new Date().toISOString()} Calling API DeleteRule`); + return this.kbnClient + .request({ + path: '/api/detection_engine/rules', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'DELETE', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async deleteTimelines(props: DeleteTimelinesProps) { + this.log.info(`${new Date().toISOString()} Calling API DeleteTimelines`); + return this.kbnClient + .request({ + path: '/api/timeline', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'DELETE', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Calculates and persists Risk Scores for an entity, returning the calculated risk score. + */ + async deprecatedTriggerRiskScoreCalculation(props: DeprecatedTriggerRiskScoreCalculationProps) { + this.log.info(`${new Date().toISOString()} Calling API DeprecatedTriggerRiskScoreCalculation`); + return this.kbnClient + .request({ + path: '/api/risk_scores/calculation/entity', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async disableRiskEngine() { + this.log.info(`${new Date().toISOString()} Calling API DisableRiskEngine`); + return this.kbnClient + .request({ + path: '/internal/risk_score/engine/disable', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'POST', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async enableRiskEngine() { + this.log.info(`${new Date().toISOString()} Calling API EnableRiskEngine`); + return this.kbnClient + .request({ + path: '/internal/risk_score/engine/enable', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'POST', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Run a shell command on an endpoint. + */ + async endpointExecuteAction(props: EndpointExecuteActionProps) { + this.log.info(`${new Date().toISOString()} Calling API EndpointExecuteAction`); + return this.kbnClient + .request({ + path: '/api/endpoint/action/execute', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Download a file from an endpoint. + */ + async endpointFileDownload(props: EndpointFileDownloadProps) { + this.log.info(`${new Date().toISOString()} Calling API EndpointFileDownload`); + return this.kbnClient + .request({ + path: replaceParams( + '/api/endpoint/action/{action_id}/file/{file_id}/download', + props.params + ), + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Get information for the specified file using the file ID. + */ + async endpointFileInfo(props: EndpointFileInfoProps) { + this.log.info(`${new Date().toISOString()} Calling API EndpointFileInfo`); + return this.kbnClient + .request({ + path: replaceParams('/api/endpoint/action/{action_id}/file/{file_id}', props.params), + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Get the details of a response action using the action ID. + */ + async endpointGetActionsDetails(props: EndpointGetActionsDetailsProps) { + this.log.info(`${new Date().toISOString()} Calling API EndpointGetActionsDetails`); + return this.kbnClient + .request({ + path: replaceParams('/api/endpoint/action/{action_id}', props.params), + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Get a list of all response actions. + */ + async endpointGetActionsList(props: EndpointGetActionsListProps) { + this.log.info(`${new Date().toISOString()} Calling API EndpointGetActionsList`); + return this.kbnClient + .request({ + path: '/api/endpoint/action', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Get a response actions state, which reports whether encryption is enabled. + */ + async endpointGetActionsState() { + this.log.info(`${new Date().toISOString()} Calling API EndpointGetActionsState`); + return this.kbnClient + .request({ + path: '/api/endpoint/action/state', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Get the status of response actions for the specified agent IDs. + */ + async endpointGetActionsStatus(props: EndpointGetActionsStatusProps) { + this.log.info(`${new Date().toISOString()} Calling API EndpointGetActionsStatus`); + return this.kbnClient + .request({ + path: '/api/endpoint/action_status', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Get a file from an endpoint. + */ + async endpointGetFileAction(props: EndpointGetFileActionProps) { + this.log.info(`${new Date().toISOString()} Calling API EndpointGetFileAction`); + return this.kbnClient + .request({ + path: '/api/endpoint/action/get_file', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Get a list of all processes running on an endpoint. + */ + async endpointGetProcessesAction(props: EndpointGetProcessesActionProps) { + this.log.info(`${new Date().toISOString()} Calling API EndpointGetProcessesAction`); + return this.kbnClient + .request({ + path: '/api/endpoint/action/running_procs', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Isolate an endpoint from the network. The endpoint remains isolated until it's released. + */ + async endpointIsolateAction(props: EndpointIsolateActionProps) { + this.log.info(`${new Date().toISOString()} Calling API EndpointIsolateAction`); + return this.kbnClient + .request({ + path: '/api/endpoint/action/isolate', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Isolate an endpoint from the network. +> info +> This URL will return a 308 permanent redirect to `POST :/api/endpoint/action/isolate`. + + */ + async endpointIsolateRedirect(props: EndpointIsolateRedirectProps) { + this.log.info(`${new Date().toISOString()} Calling API EndpointIsolateRedirect`); + return this.kbnClient + .request({ + path: '/api/endpoint/isolate', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Terminate a running process on an endpoint. + */ + async endpointKillProcessAction(props: EndpointKillProcessActionProps) { + this.log.info(`${new Date().toISOString()} Calling API EndpointKillProcessAction`); + return this.kbnClient + .request({ + path: '/api/endpoint/action/kill_process', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Scan a specific file or directory on an endpoint for malware. + */ + async endpointScanAction(props: EndpointScanActionProps) { + this.log.info(`${new Date().toISOString()} Calling API EndpointScanAction`); + return this.kbnClient + .request({ + path: '/api/endpoint/action/scan', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Suspend a running process on an endpoint. + */ + async endpointSuspendProcessAction(props: EndpointSuspendProcessActionProps) { + this.log.info(`${new Date().toISOString()} Calling API EndpointSuspendProcessAction`); + return this.kbnClient + .request({ + path: '/api/endpoint/action/suspend_process', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Release an isolated endpoint, allowing it to rejoin a network. + */ + async endpointUnisolateAction(props: EndpointUnisolateActionProps) { + this.log.info(`${new Date().toISOString()} Calling API EndpointUnisolateAction`); + return this.kbnClient + .request({ + path: '/api/endpoint/action/unisolate', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Release an isolated endpoint, allowing it to rejoin a network. +> info +> This URL will return a 308 permanent redirect to `POST :/api/endpoint/action/unisolate`. + + */ + async endpointUnisolateRedirect(props: EndpointUnisolateRedirectProps) { + this.log.info(`${new Date().toISOString()} Calling API EndpointUnisolateRedirect`); + return this.kbnClient + .request({ + path: '/api/endpoint/unisolate', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Upload a file to an endpoint. + */ + async endpointUploadAction(props: EndpointUploadActionProps) { + this.log.info(`${new Date().toISOString()} Calling API EndpointUploadAction`); + return this.kbnClient + .request({ + path: '/api/endpoint/action/upload', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Export detection rules to an `.ndjson` file. The following configuration items are also included in the `.ndjson` file: +- Actions +- Exception lists +> info +> You cannot export prebuilt rules. + + */ + async exportRules(props: ExportRulesProps) { + this.log.info(`${new Date().toISOString()} Calling API ExportRules`); + return this.kbnClient + .request({ + path: '/api/detection_engine/rules/_export', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async exportTimelines(props: ExportTimelinesProps) { + this.log.info(`${new Date().toISOString()} Calling API ExportTimelines`); + return this.kbnClient + .request({ + path: '/api/timeline/_export', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Finalize successful migrations of detection alerts. This replaces the original index's alias with the successfully migrated index's alias. +The endpoint is idempotent; therefore, it can safely be used to poll a given migration and, upon completion, +finalize it. + + */ + async finalizeAlertsMigration(props: FinalizeAlertsMigrationProps) { + this.log.info(`${new Date().toISOString()} Calling API FinalizeAlertsMigration`); + return this.kbnClient + .request({ + path: '/api/detection_engine/signals/finalize_migration', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * List asset criticality records, paging, sorting and filtering as needed. + */ + async findAssetCriticalityRecords(props: FindAssetCriticalityRecordsProps) { + this.log.info(`${new Date().toISOString()} Calling API FindAssetCriticalityRecords`); + return this.kbnClient + .request({ + path: '/api/asset_criticality/list', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Retrieve a paginated list of detection rules. By default, the first page is returned, with 20 results per page. + */ + async findRules(props: FindRulesProps) { + this.log.info(`${new Date().toISOString()} Calling API FindRules`); + return this.kbnClient + .request({ + path: '/api/detection_engine/rules/_find', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async getAgentPolicySummary(props: GetAgentPolicySummaryProps) { + this.log.info(`${new Date().toISOString()} Calling API GetAgentPolicySummary`); + return this.kbnClient + .request({ + path: '/api/endpoint/policy/summaries', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Get the criticality record for a specific asset. + */ + async getAssetCriticalityRecord(props: GetAssetCriticalityRecordProps) { + this.log.info(`${new Date().toISOString()} Calling API GetAssetCriticalityRecord`); + return this.kbnClient + .request({ + path: '/api/asset_criticality', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async getAssetCriticalityStatus() { + this.log.info(`${new Date().toISOString()} Calling API GetAssetCriticalityStatus`); + return this.kbnClient + .request({ + path: '/internal/asset_criticality/status', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async getDraftTimelines(props: GetDraftTimelinesProps) { + this.log.info(`${new Date().toISOString()} Calling API GetDraftTimelines`); + return this.kbnClient + .request({ + path: '/api/timeline/_draft', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async getEndpointMetadataList(props: GetEndpointMetadataListProps) { + this.log.info(`${new Date().toISOString()} Calling API GetEndpointMetadataList`); + return this.kbnClient + .request({ + path: '/api/endpoint/metadata', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async getEndpointSuggestions(props: GetEndpointSuggestionsProps) { + this.log.info(`${new Date().toISOString()} Calling API GetEndpointSuggestions`); + return this.kbnClient + .request({ + path: replaceParams('/api/endpoint/suggestions/{suggestion_type}', props.params), + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Gets notes + */ + async getNotes(props: GetNotesProps) { + this.log.info(`${new Date().toISOString()} Calling API GetNotes`); + return this.kbnClient + .request({ + path: '/api/note', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async getPolicyResponse(props: GetPolicyResponseProps) { + this.log.info(`${new Date().toISOString()} Calling API GetPolicyResponse`); + return this.kbnClient + .request({ + path: '/api/endpoint/policy_response', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async getProtectionUpdatesNote(props: GetProtectionUpdatesNoteProps) { + this.log.info(`${new Date().toISOString()} Calling API GetProtectionUpdatesNote`); + return this.kbnClient + .request({ + path: replaceParams( + '/api/endpoint/protection_updates_note/{package_policy_id}', + props.params + ), + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Returns the status of both the legacy transform-based risk engine, as well as the new risk engine + */ + async getRiskEngineStatus() { + this.log.info(`${new Date().toISOString()} Calling API GetRiskEngineStatus`); + return this.kbnClient + .request({ + path: '/internal/risk_score/engine/status', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async getRuleExecutionEvents(props: GetRuleExecutionEventsProps) { + this.log.info(`${new Date().toISOString()} Calling API GetRuleExecutionEvents`); + return this.kbnClient + .request({ + path: replaceParams( + '/internal/detection_engine/rules/{ruleId}/execution/events', + props.params + ), + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'PUT', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async getRuleExecutionResults(props: GetRuleExecutionResultsProps) { + this.log.info(`${new Date().toISOString()} Calling API GetRuleExecutionResults`); + return this.kbnClient + .request({ + path: replaceParams( + '/internal/detection_engine/rules/{ruleId}/execution/results', + props.params + ), + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'PUT', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async getTimeline(props: GetTimelineProps) { + this.log.info(`${new Date().toISOString()} Calling API GetTimeline`); + return this.kbnClient + .request({ + path: '/api/timeline', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async getTimelines(props: GetTimelinesProps) { + this.log.info(`${new Date().toISOString()} Calling API GetTimelines`); + return this.kbnClient + .request({ + path: '/api/timelines', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Import detection rules from an `.ndjson` file, including actions and exception lists. The request must include: +- The `Content-Type: multipart/form-data` HTTP header. +- A link to the `.ndjson` file containing the rules. + + */ + async importRules(props: ImportRulesProps) { + this.log.info(`${new Date().toISOString()} Calling API ImportRules`); + return this.kbnClient + .request({ + path: '/api/detection_engine/rules/_import', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.attachment, + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async importTimelines(props: ImportTimelinesProps) { + this.log.info(`${new Date().toISOString()} Calling API ImportTimelines`); + return this.kbnClient + .request({ + path: '/api/timeline/_import', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Initializes the Risk Engine by creating the necessary indices and mappings, removing old transforms, and starting the new risk engine + */ + async initRiskEngine() { + this.log.info(`${new Date().toISOString()} Calling API InitRiskEngine`); + return this.kbnClient + .request({ + path: '/internal/risk_score/engine/init', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'POST', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Install and update all Elastic prebuilt detection rules and Timelines. + */ + async installPrebuiltRulesAndTimelines() { + this.log.info(`${new Date().toISOString()} Calling API InstallPrebuiltRulesAndTimelines`); + return this.kbnClient + .request({ + path: '/api/detection_engine/rules/prepackaged', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PUT', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async installPrepackedTimelines(props: InstallPrepackedTimelinesProps) { + this.log.info(`${new Date().toISOString()} Calling API InstallPrepackedTimelines`); + return this.kbnClient + .request({ + path: '/api/timeline/_prepackaged', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async internalUploadAssetCriticalityRecords(props: InternalUploadAssetCriticalityRecordsProps) { + this.log.info(`${new Date().toISOString()} Calling API InternalUploadAssetCriticalityRecords`); + return this.kbnClient + .request({ + path: '/internal/asset_criticality/upload_csv', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'POST', + body: props.attachment, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Update specific fields of an existing detection rule using the `rule_id` or `id` field. + */ + async patchRule(props: PatchRuleProps) { + this.log.info(`${new Date().toISOString()} Calling API PatchRule`); + return this.kbnClient + .request({ + path: '/api/detection_engine/rules', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PATCH', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Updates an existing timeline. This API is used to update the title, description, date range, pinned events, pinned queries, and/or pinned saved queries of an existing timeline. + */ + async patchTimeline(props: PatchTimelineProps) { + this.log.info(`${new Date().toISOString()} Calling API PatchTimeline`); + return this.kbnClient + .request({ + path: '/api/timeline', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PATCH', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Apply a bulk action, such as bulk edit, duplicate, or delete, to multiple detection rules. The bulk action is applied to all rules that match the query or to the rules listed by their IDs. + */ + async performRulesBulkAction(props: PerformRulesBulkActionProps) { + this.log.info(`${new Date().toISOString()} Calling API PerformRulesBulkAction`); + return this.kbnClient + .request({ + path: '/api/detection_engine/rules/_bulk_action', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async persistFavoriteRoute(props: PersistFavoriteRouteProps) { + this.log.info(`${new Date().toISOString()} Calling API PersistFavoriteRoute`); + return this.kbnClient + .request({ + path: '/api/timeline/_favorite', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PATCH', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async persistNoteRoute(props: PersistNoteRouteProps) { + this.log.info(`${new Date().toISOString()} Calling API PersistNoteRoute`); + return this.kbnClient + .request({ + path: '/api/note', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PATCH', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async persistPinnedEventRoute(props: PersistPinnedEventRouteProps) { + this.log.info(`${new Date().toISOString()} Calling API PersistPinnedEventRoute`); + return this.kbnClient + .request({ + path: '/api/pinned_event', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PATCH', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Calculates and returns a list of Risk Scores, sorted by identifier_type and risk score. + */ + async previewRiskScore(props: PreviewRiskScoreProps) { + this.log.info(`${new Date().toISOString()} Calling API PreviewRiskScore`); + return this.kbnClient + .request({ + path: '/internal/risk_score/preview', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async readAlertsIndex() { + this.log.info(`${new Date().toISOString()} Calling API ReadAlertsIndex`); + return this.kbnClient + .request({ + path: '/api/detection_engine/index', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Retrieve indices that contain detection alerts of a particular age, along with migration information for each of those indices. + */ + async readAlertsMigrationStatus(props: ReadAlertsMigrationStatusProps) { + this.log.info(`${new Date().toISOString()} Calling API ReadAlertsMigrationStatus`); + return this.kbnClient + .request({ + path: '/api/detection_engine/signals/migration_status', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Retrieve the status of all Elastic prebuilt detection rules and Timelines. + */ + async readPrebuiltRulesAndTimelinesStatus() { + this.log.info(`${new Date().toISOString()} Calling API ReadPrebuiltRulesAndTimelinesStatus`); + return this.kbnClient + .request({ + path: '/api/detection_engine/rules/prepackaged/_status', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Retrieves whether or not the user is authenticated, and the user's Kibana +space and index privileges, which determine if the user can create an +index for the Elastic Security alerts generated by +detection engine rules. + + */ + async readPrivileges() { + this.log.info(`${new Date().toISOString()} Calling API ReadPrivileges`); + return this.kbnClient + .request({ + path: '/api/detection_engine/privileges', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async readRiskEngineSettings() { + this.log.info(`${new Date().toISOString()} Calling API ReadRiskEngineSettings`); + return this.kbnClient + .request({ + path: '/internal/risk_score/engine/settings', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Retrieve a detection rule using the `rule_id` or `id` field. + */ + async readRule(props: ReadRuleProps) { + this.log.info(`${new Date().toISOString()} Calling API ReadRule`); + return this.kbnClient + .request({ + path: '/api/detection_engine/rules', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * List all unique tags from all detection rules. + */ + async readTags() { + this.log.info(`${new Date().toISOString()} Calling API ReadTags`); + return this.kbnClient + .request({ + path: '/api/detection_engine/tags', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async resolveTimeline(props: ResolveTimelineProps) { + this.log.info(`${new Date().toISOString()} Calling API ResolveTimeline`); + return this.kbnClient + .request({ + path: '/api/timeline/resolve', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async riskEngineGetPrivileges() { + this.log.info(`${new Date().toISOString()} Calling API RiskEngineGetPrivileges`); + return this.kbnClient + .request({ + path: '/internal/risk_engine/privileges', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async rulePreview(props: RulePreviewProps) { + this.log.info(`${new Date().toISOString()} Calling API RulePreview`); + return this.kbnClient + .request({ + path: '/api/detection_engine/rules/preview', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async scheduleRiskEngineNow() { + this.log.info(`${new Date().toISOString()} Calling API ScheduleRiskEngineNow`); + return this.kbnClient + .request({ + path: '/api/risk_score/engine/schedule_now', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Find and/or aggregate detection alerts that match the given query. + */ + async searchAlerts(props: SearchAlertsProps) { + this.log.info(`${new Date().toISOString()} Calling API SearchAlerts`); + return this.kbnClient + .request({ + path: '/api/detection_engine/signals/search', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Assign users to detection alerts, and unassign them from alerts. +> info +> You cannot add and remove the same assignee in the same request. + + */ + async setAlertAssignees(props: SetAlertAssigneesProps) { + this.log.info(`${new Date().toISOString()} Calling API SetAlertAssignees`); + return this.kbnClient + .request({ + path: '/api/detection_engine/signals/assignees', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Set the status of one or more detection alerts. + */ + async setAlertsStatus(props: SetAlertsStatusProps) { + this.log.info(`${new Date().toISOString()} Calling API SetAlertsStatus`); + return this.kbnClient + .request({ + path: '/api/detection_engine/signals/status', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * And tags to detection alerts, and remove them from alerts. +> info +> You cannot add and remove the same alert tag in the same request. + + */ + async setAlertTags(props: SetAlertTagsProps) { + this.log.info(`${new Date().toISOString()} Calling API SetAlertTags`); + return this.kbnClient + .request({ + path: '/api/detection_engine/signals/tags', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Suggests user profiles. + */ + async suggestUserProfiles(props: SuggestUserProfilesProps) { + this.log.info(`${new Date().toISOString()} Calling API SuggestUserProfiles`); + return this.kbnClient + .request({ + path: '/internal/detection_engine/users/_find', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'POST', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Calculates and persists Risk Scores for an entity, returning the calculated risk score. + */ + async triggerRiskScoreCalculation(props: TriggerRiskScoreCalculationProps) { + this.log.info(`${new Date().toISOString()} Calling API TriggerRiskScoreCalculation`); + return this.kbnClient + .request({ + path: '/internal/risk_score/calculation/entity', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Update a detection rule using the `rule_id` or `id` field. The original rule is replaced, and all unspecified fields are deleted. +> info +> You cannot modify the `id` or `rule_id` values. + + */ + async updateRule(props: UpdateRuleProps) { + this.log.info(`${new Date().toISOString()} Calling API UpdateRule`); + return this.kbnClient + .request({ + path: '/api/detection_engine/rules', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PUT', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async uploadAssetCriticalityRecords(props: UploadAssetCriticalityRecordsProps) { + this.log.info(`${new Date().toISOString()} Calling API UploadAssetCriticalityRecords`); + return this.kbnClient + .request({ + path: '/api/asset_criticality/upload_csv', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'POST', + body: props.attachment, + }) + .catch(catchAxiosErrorFormatAndThrow); + } +} + +export interface AlertsMigrationCleanupProps { + body: AlertsMigrationCleanupRequestBodyInput; +} +export interface BulkCreateRulesProps { + body: BulkCreateRulesRequestBodyInput; +} +export interface BulkDeleteRulesProps { + body: BulkDeleteRulesRequestBodyInput; +} +export interface BulkDeleteRulesPostProps { + body: BulkDeleteRulesPostRequestBodyInput; +} +export interface BulkPatchRulesProps { + body: BulkPatchRulesRequestBodyInput; +} +export interface BulkUpdateRulesProps { + body: BulkUpdateRulesRequestBodyInput; +} +export interface BulkUpsertAssetCriticalityRecordsProps { + body: BulkUpsertAssetCriticalityRecordsRequestBodyInput; +} +export interface CleanDraftTimelinesProps { + body: CleanDraftTimelinesRequestBodyInput; +} +export interface CreateAlertsMigrationProps { + body: CreateAlertsMigrationRequestBodyInput; +} +export interface CreateAssetCriticalityRecordProps { + body: CreateAssetCriticalityRecordRequestBodyInput; +} +export interface CreateRuleProps { + body: CreateRuleRequestBodyInput; +} +export interface CreateTimelinesProps { + body: CreateTimelinesRequestBodyInput; +} +export interface CreateUpdateProtectionUpdatesNoteProps { + params: CreateUpdateProtectionUpdatesNoteRequestParamsInput; + body: CreateUpdateProtectionUpdatesNoteRequestBodyInput; +} +export interface DeleteAssetCriticalityRecordProps { + query: DeleteAssetCriticalityRecordRequestQueryInput; +} +export interface DeleteNoteProps { + body: DeleteNoteRequestBodyInput; +} +export interface DeleteRuleProps { + query: DeleteRuleRequestQueryInput; +} +export interface DeleteTimelinesProps { + body: DeleteTimelinesRequestBodyInput; +} +export interface DeprecatedTriggerRiskScoreCalculationProps { + body: DeprecatedTriggerRiskScoreCalculationRequestBodyInput; +} +export interface EndpointExecuteActionProps { + body: EndpointExecuteActionRequestBodyInput; +} +export interface EndpointFileDownloadProps { + params: EndpointFileDownloadRequestParamsInput; +} +export interface EndpointFileInfoProps { + params: EndpointFileInfoRequestParamsInput; +} +export interface EndpointGetActionsDetailsProps { + params: EndpointGetActionsDetailsRequestParamsInput; +} +export interface EndpointGetActionsListProps { + query: EndpointGetActionsListRequestQueryInput; +} +export interface EndpointGetActionsStatusProps { + query: EndpointGetActionsStatusRequestQueryInput; +} +export interface EndpointGetFileActionProps { + body: EndpointGetFileActionRequestBodyInput; +} +export interface EndpointGetProcessesActionProps { + body: EndpointGetProcessesActionRequestBodyInput; +} +export interface EndpointIsolateActionProps { + body: EndpointIsolateActionRequestBodyInput; +} +export interface EndpointIsolateRedirectProps { + body: EndpointIsolateRedirectRequestBodyInput; +} +export interface EndpointKillProcessActionProps { + body: EndpointKillProcessActionRequestBodyInput; +} +export interface EndpointScanActionProps { + body: EndpointScanActionRequestBodyInput; +} +export interface EndpointSuspendProcessActionProps { + body: EndpointSuspendProcessActionRequestBodyInput; +} +export interface EndpointUnisolateActionProps { + body: EndpointUnisolateActionRequestBodyInput; +} +export interface EndpointUnisolateRedirectProps { + body: EndpointUnisolateRedirectRequestBodyInput; +} +export interface EndpointUploadActionProps { + body: EndpointUploadActionRequestBodyInput; +} +export interface ExportRulesProps { + query: ExportRulesRequestQueryInput; + body: ExportRulesRequestBodyInput; +} +export interface ExportTimelinesProps { + query: ExportTimelinesRequestQueryInput; + body: ExportTimelinesRequestBodyInput; +} +export interface FinalizeAlertsMigrationProps { + body: FinalizeAlertsMigrationRequestBodyInput; +} +export interface FindAssetCriticalityRecordsProps { + query: FindAssetCriticalityRecordsRequestQueryInput; +} +export interface FindRulesProps { + query: FindRulesRequestQueryInput; +} +export interface GetAgentPolicySummaryProps { + query: GetAgentPolicySummaryRequestQueryInput; +} +export interface GetAssetCriticalityRecordProps { + query: GetAssetCriticalityRecordRequestQueryInput; +} +export interface GetDraftTimelinesProps { + query: GetDraftTimelinesRequestQueryInput; +} +export interface GetEndpointMetadataListProps { + query: GetEndpointMetadataListRequestQueryInput; +} +export interface GetEndpointSuggestionsProps { + params: GetEndpointSuggestionsRequestParamsInput; + body: GetEndpointSuggestionsRequestBodyInput; +} +export interface GetNotesProps { + query: GetNotesRequestQueryInput; +} +export interface GetPolicyResponseProps { + query: GetPolicyResponseRequestQueryInput; +} +export interface GetProtectionUpdatesNoteProps { + params: GetProtectionUpdatesNoteRequestParamsInput; +} +export interface GetRuleExecutionEventsProps { + query: GetRuleExecutionEventsRequestQueryInput; + params: GetRuleExecutionEventsRequestParamsInput; +} +export interface GetRuleExecutionResultsProps { + query: GetRuleExecutionResultsRequestQueryInput; + params: GetRuleExecutionResultsRequestParamsInput; +} +export interface GetTimelineProps { + query: GetTimelineRequestQueryInput; +} +export interface GetTimelinesProps { + query: GetTimelinesRequestQueryInput; +} +export interface ImportRulesProps { + query: ImportRulesRequestQueryInput; + attachment: FormData; +} +export interface ImportTimelinesProps { + body: ImportTimelinesRequestBodyInput; +} +export interface InstallPrepackedTimelinesProps { + body: InstallPrepackedTimelinesRequestBodyInput; +} +export interface InternalUploadAssetCriticalityRecordsProps { + attachment: FormData; +} +export interface PatchRuleProps { + body: PatchRuleRequestBodyInput; +} +export interface PatchTimelineProps { + body: PatchTimelineRequestBodyInput; +} +export interface PerformRulesBulkActionProps { + query: PerformRulesBulkActionRequestQueryInput; + body: PerformRulesBulkActionRequestBodyInput; +} +export interface PersistFavoriteRouteProps { + body: PersistFavoriteRouteRequestBodyInput; +} +export interface PersistNoteRouteProps { + body: PersistNoteRouteRequestBodyInput; +} +export interface PersistPinnedEventRouteProps { + body: PersistPinnedEventRouteRequestBodyInput; +} +export interface PreviewRiskScoreProps { + body: PreviewRiskScoreRequestBodyInput; +} +export interface ReadAlertsMigrationStatusProps { + query: ReadAlertsMigrationStatusRequestQueryInput; +} +export interface ReadRuleProps { + query: ReadRuleRequestQueryInput; +} +export interface ResolveTimelineProps { + query: ResolveTimelineRequestQueryInput; +} +export interface RulePreviewProps { + body: RulePreviewRequestBodyInput; +} +export interface SearchAlertsProps { + body: SearchAlertsRequestBodyInput; +} +export interface SetAlertAssigneesProps { + body: SetAlertAssigneesRequestBodyInput; +} +export interface SetAlertsStatusProps { + body: SetAlertsStatusRequestBodyInput; +} +export interface SetAlertTagsProps { + body: SetAlertTagsRequestBodyInput; +} +export interface SuggestUserProfilesProps { + query: SuggestUserProfilesRequestQueryInput; +} +export interface TriggerRiskScoreCalculationProps { + body: TriggerRiskScoreCalculationRequestBodyInput; +} +export interface UpdateRuleProps { + body: UpdateRuleRequestBodyInput; +} +export interface UploadAssetCriticalityRecordsProps { + attachment: FormData; +} diff --git a/x-pack/plugins/security_solution/scripts/openapi/generate.js b/x-pack/plugins/security_solution/scripts/openapi/generate.js index adfe11192ae49..bab9fa5f36cc6 100644 --- a/x-pack/plugins/security_solution/scripts/openapi/generate.js +++ b/x-pack/plugins/security_solution/scripts/openapi/generate.js @@ -12,6 +12,8 @@ const { resolve, join } = require('path'); const SECURITY_SOLUTION_ROOT = resolve(__dirname, '../..'); +// This script is also run in CI: to track down the scripts that run it in CI, code search for `yarn openapi:generate` in the `.buildkite` top level directory + (async () => { await generate({ title: 'API route schemas', @@ -30,4 +32,18 @@ const SECURITY_SOLUTION_ROOT = resolve(__dirname, '../..'); outFile: join(REPO_ROOT, 'x-pack/test/api_integration/services/security_solution_api.gen.ts'), }, }); + + await generate({ + title: 'API client for quickstart', + rootDir: SECURITY_SOLUTION_ROOT, + sourceGlob: './common/**/*.schema.yaml', + templateName: 'api_client_quickstart', + skipLinting: false, + bundle: { + outFile: join( + REPO_ROOT, + 'x-pack/plugins/security_solution/common/api/quickstart_client.gen.ts' + ), + }, + }); })(); diff --git a/x-pack/plugins/security_solution/scripts/quickstart/README.md b/x-pack/plugins/security_solution/scripts/quickstart/README.md new file mode 100644 index 0000000000000..997762a82a27d --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/quickstart/README.md @@ -0,0 +1,136 @@ +# Quickstart for Developers + +These tools make it fast and easy to create detection rules, exceptions, value lists, and source data for testing. + +## Usage + +`node x-pack/plugins/security_solution/scripts/quickstart/run.js`: Runs the script defined in `scratchpad.ts` +Options: +--username: User name to be used for auth against elasticsearch and kibana (Default: elastic). +--password: User name Password (Default: changeme) +--kibana: The url to Kibana (Default: http://127.0.0.1:5601). In most cases you'll want to set this URL to include the basepath as well. +--apikey: The API key for authentication, overrides username/password - use for serverless projects + +`scratchpad.ts` already contains code to set up clients for Elasticsearch and Kibana. In addition it provides clients for Security Solution, Lists, and Exceptions APIs, built on top of the Kibana client. However, it does not create any rules/exceptions/lists/data - it's a blank slate for you to immediately begin creating the resources you want for testing. Please don't commit data-generating code to `scratchpad.ts`! Instead, when you have built a data-generating script that might be useful to others, please extract the useful components to the `quickstart/modules` folder and leave `scratchpad.ts` empty for the next developer. + +### Environments + +The API clients are designed to work with any delivery method - local, cloud, or serverless deployments. For deployments that do not allow username/password auth, use an API key. + +## Modules + +Extracting data-generating logic into reusable modules that other people will actually use is the hardest part of sharing these scripts. To that end, it's crucial that the modules are organized as neatly as possible and extremely clear about what they do. If the modules are even slightly confusing, it will be faster for people to rebuild the same logic than to figure out how the existing scripts work. + +### Data + +Functions to create documents with various properties. This initial implementation has a function to create a document with an arbitrary number of fields and arbitrary amount of data in each field, but should be extended with more functions to create sets of documents with specific relationships such as X total documents with Y number of unique hosts etc. + +### Entity Analytics + +Functions to help install fake entity analytics data. Useful for testing alert enrichment based on entity analytics. + +### Exceptions + +Functions to help create exceptions with various properties. For example, one helper takes an array of values and automatically creates a value list exception item from that array - internally, it creates the value list and an exception item that references the list. + +### Frozen (TODO) + +Functions to help create frozen tier data quickly. These functions (once implemented) will take existing data and immediately move it to frozen for test purposes. + +### Lists + +Functions to help interact with the Lists APIs. The initial helper function makes it easy to import a value list from an array, since the process of attaching a file to a request (as the API expects) is not that intuitive. + +### Mappings + +Functions to help setup mappings. Provides the ECS mapping as well as helpers to generate mappings with tons of fields. + +### Rules + +Functions to help create rules along with data specific to each rule (WIP). Each sample rule defined in this folder should have an associated function to generate data that triggers alerts for the rule. + +## Speed + +To run a number of API requests in parallel, use `concurrentlyExec` from @kbn/securitysolution-utils. + +## Examples + +### Create a Rule + +``` +// Extra imports +import { concurrentlyExec } from '@kbn/securitysolution-utils/src/client_concurrency'; +import { basicRule } from './modules/rules/new_terms/basic_rule'; +import { duplicateRuleParams } from './modules/rules'; + +// ... omitted client setup stuff + +// Core logic +const ruleCopies = duplicateRuleParams(basicRule, 200); +const functions = ruleCopies.map((rule) => () => detectionsClient.createRule({ body: rule })); +const responses = await concurrentlyExec(functions); +``` + +### Create 200 Rules and an Exception for each one + +``` +// Extra imports +import { concurrentlyExec } from '@kbn/securitysolution-utils/src/client_concurrency'; +import { basicRule } from './modules/rules/new_terms/basic_rule'; +import { duplicateRuleParams } from './modules/rules'; +import { buildCreateRuleExceptionListItemsProps } from './modules/exceptions'; + +// ... omitted client setup stuff + +// Core logic +const ruleCopies = duplicateRuleParams(basicRule, 200); +const response = await detectionsClient.bulkCreateRules({ body: ruleCopies }); +const createdRules: RuleResponse[] = response.data.filter( +(r) => r.id != null +) as RuleResponse[]; + +// This map looks a bit confusing, but the concept is simple: take the rules we just created and +// create a *function* per rule to create an exception for that rule. We want a function to call later instead of just +// calling the API immediately to limit the number of requests in flight (with `concurrentlyExec`) +const exceptionsFunctions = createdRules.map( +(r) => () => + exceptionsClient.createRuleExceptionListItems( + buildCreateRuleExceptionListItemsProps({ id: r.id }) + ) +); +const exceptionsResponses = await concurrentlyExec(exceptionsFunctions); +``` + +### Run 10 Rule Preview Requests Simultaneously + +``` +const previewPromises = range(50).map( + (idx) => () => + detectionsClient.rulePreview({ + body: { + ...getBasicRuleMetadata(), + type: 'query', + timeframeEnd: '2024-08-21T20:37:37.114Z', + invocationCount: 1, + from: 'now-6m', + interval: '5m', + index: [index], + query: '*', + }, + }) +); + +const results = (await concurrentlyExec(previewPromises, 50)).map( + (result) => result.data.logs +); +``` + +## Future Work + +### Interactive Mode + +It may be useful to have a mode where the CLI waits for input from the user and creates resources selected from a predefined list. + +### Resource Tracking/Cleanup + +It may also be useful to have the tooling automatically keep track of the created resources so they can be deleted automatically when finished. diff --git a/x-pack/plugins/security_solution/scripts/quickstart/modules/data/index.ts b/x-pack/plugins/security_solution/scripts/quickstart/modules/data/index.ts new file mode 100644 index 0000000000000..d4ae7a0f52b26 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/quickstart/modules/data/index.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 { range } from 'lodash'; +import crypto from 'crypto'; + +/** + * A basic function to generate random data filling out a document. Useful for forcing + * Elasticsearch to handle large amounts of data in a single doc. + * @param numFields Number of fields to generate in each document + * @param fieldSize Number of bytes to generate for each field + * @returns Object representing the new document + */ +export const buildLargeDocument = ({ + numFields, + fieldSize, +}: { + numFields: number; + fieldSize: number; +}): Record => { + const doc: Record = {}; + range(numFields).forEach((idx) => { + doc[`field_${idx}`] = crypto.randomBytes(fieldSize).toString('hex'); + }); + return doc; +}; + +export const addTimestampToDoc = ({ + timestamp = new Date(), + doc, +}: { + timestamp?: Date; + doc: Record; +}): Record => { + doc['@timestamp'] = timestamp; + return doc; +}; + +export const addFieldToDoc = ({ + fieldName, + fieldValue, + doc, +}: { + fieldName: string; + fieldValue: unknown; + doc: Record; +}): Record => { + doc[fieldName] = fieldValue; + return doc; +}; diff --git a/x-pack/plugins/security_solution/scripts/quickstart/modules/entity_analytics/index.ts b/x-pack/plugins/security_solution/scripts/quickstart/modules/entity_analytics/index.ts new file mode 100644 index 0000000000000..4ff4e08a113d7 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/quickstart/modules/entity_analytics/index.ts @@ -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 type { Client } from '@elastic/elasticsearch'; +import type { MappingTypeMapping } from '@elastic/elasticsearch/lib/api/types'; +import { getRiskScoreLatestIndex } from '../../../../common/entity_analytics/risk_engine'; + +export const getRiskScoreIndexMappings: () => MappingTypeMapping = () => ({ + dynamic: 'false', + properties: { + '@timestamp': { + type: 'date', + }, + host: { + properties: { + name: { + type: 'keyword', + }, + risk: { + properties: { + calculated_level: { + type: 'keyword', + }, + calculated_score: { + type: 'float', + }, + calculated_score_norm: { + type: 'float', + }, + category_1_count: { + type: 'long', + }, + category_1_score: { + type: 'float', + }, + id_field: { + type: 'keyword', + }, + id_value: { + type: 'keyword', + }, + inputs: { + properties: { + category: { + type: 'keyword', + }, + description: { + type: 'keyword', + }, + id: { + type: 'keyword', + }, + index: { + type: 'keyword', + }, + risk_score: { + type: 'float', + }, + timestamp: { + type: 'date', + }, + }, + }, + notes: { + type: 'keyword', + }, + }, + }, + }, + }, + user: { + properties: { + name: { + type: 'keyword', + }, + risk: { + properties: { + calculated_level: { + type: 'keyword', + }, + calculated_score: { + type: 'float', + }, + calculated_score_norm: { + type: 'float', + }, + category_1_count: { + type: 'long', + }, + category_1_score: { + type: 'float', + }, + id_field: { + type: 'keyword', + }, + id_value: { + type: 'keyword', + }, + inputs: { + properties: { + category: { + type: 'keyword', + }, + description: { + type: 'keyword', + }, + id: { + type: 'keyword', + }, + index: { + type: 'keyword', + }, + risk_score: { + type: 'float', + }, + timestamp: { + type: 'date', + }, + }, + }, + notes: { + type: 'keyword', + }, + }, + }, + }, + }, + }, +}); + +export const createRiskScoreIndex = async ({ client }: { client: Client }) => { + const riskScoreIndexName = getRiskScoreLatestIndex(); + await client.indices.create({ + index: riskScoreIndexName, + mappings: getRiskScoreIndexMappings(), + }); +}; + +export const addRiskScoreDoc = async ({ client }: { client: Client }) => { + const riskScoreIndexName = getRiskScoreLatestIndex(); + await client.index({ + index: riskScoreIndexName, + document: { + host: { + name: 'test host', + risk: { calculated_level: 'low', calculated_score: 21, calculated_score_norm: 51 }, + }, + }, + }); +}; diff --git a/x-pack/plugins/security_solution/scripts/quickstart/modules/exceptions/index.ts b/x-pack/plugins/security_solution/scripts/quickstart/modules/exceptions/index.ts new file mode 100644 index 0000000000000..a67a856dd1a9f --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/quickstart/modules/exceptions/index.ts @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ExceptionListItemEntry } from '@kbn/securitysolution-exceptions-common/api'; +import type { + CreateRuleExceptionListItemsProps, + Client as ExceptionsClient, +} from '@kbn/securitysolution-exceptions-common/api/quickstart_client.gen'; +import type { ListType } from '@kbn/securitysolution-lists-common/api'; +import type { Client as ListsClient } from '@kbn/securitysolution-lists-common/api/quickstart_client.gen'; +import { importListItemsWrapper } from '../lists'; + +export const getMatchEntry: () => ExceptionListItemEntry = () => ({ + type: 'match', + field: 'host.name', + value: 'host-1', + operator: 'included', +}); + +export const buildCreateRuleExceptionListItemsProps: (props: { + id: string; +}) => CreateRuleExceptionListItemsProps = ({ id }) => ({ + params: { id }, + body: { + items: [ + { + description: 'test', + type: 'simple', + name: 'test', + entries: [ + { + type: 'match', + field: 'test', + value: 'test', + operator: 'included', + }, + ], + }, + ], + }, +}); + +export const buildListExceptionListItemsProps: (props: { + id: string; + listId: string; + listType: ListType; +}) => CreateRuleExceptionListItemsProps = ({ id, listId, listType }) => ({ + params: { id }, + body: { + items: [ + { + description: 'test', + type: 'simple', + name: 'test', + entries: [ + { + type: 'list', + field: 'test', + operator: 'included', + list: { + id: listId, + type: listType, + }, + }, + ], + }, + ], + }, +}); + +export const createValueListException = async ({ + listItems, + listName = 'myList', + listType = 'keyword', + exceptionListId, + exceptionsClient, + listsClient, +}: { + listItems: string[]; + listName: string; + listType: ListType; + exceptionListId: string; + exceptionsClient: ExceptionsClient; + listsClient: ListsClient; +}) => { + await importListItemsWrapper({ + listsClient, + listName, + listFileType: 'txt', + listType, + listItems, + }); + + await exceptionsClient.createExceptionListItem({ + body: { + description: 'test', + list_id: exceptionListId, + type: 'simple', + name: 'test item', + entries: [ + { + type: 'list', + field: 'host.name', + list: { + id: `${listName}.txt`, + type: listType, + }, + operator: 'included', + }, + ], + }, + }); +}; diff --git a/x-pack/plugins/security_solution/scripts/quickstart/modules/lists/index.ts b/x-pack/plugins/security_solution/scripts/quickstart/modules/lists/index.ts new file mode 100644 index 0000000000000..fb41fe46b677c --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/quickstart/modules/lists/index.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ListType } from '@kbn/securitysolution-lists-common/api'; +import type { Client as ListsClient } from '@kbn/securitysolution-lists-common/api/quickstart_client.gen'; + +/** + * Efficiently turn an array of values into a value list in Kibana. Since the value list import API expects a file to be attached, + * this function handles turning an array into a file attachment for the API and making the appropriate request structure. + * + * @param listsClient The lists client for accessing lists APIs through the CLI tool. + * @param listName Name of the list to create. Should be unique, as this will become the list ID as well. + * @param listFileType The file type suffix to use when sending the import list request. This should have no effect on the functionality of the created list, + * it's effectively just metadata. + * @param listItems Array of values to insert into the list. + * @param listType Elasticsearch field type to use for the list values. + * @returns Created list info + */ +export const importListItemsWrapper = ({ + listsClient, + listName, + listFileType, + listItems, + listType, +}: { + listsClient: ListsClient; + listName: string; + listFileType: 'txt' | 'csv'; + listItems: unknown[]; + listType: ListType; +}) => { + const blob = new Blob([listItems.join('\r\n')], { type: 'application/json' }); + const body = new FormData(); + body.append('file', blob, `${listName}.${listFileType}`); + return listsClient.importListItems({ query: { type: listType }, attachment: body }); +}; diff --git a/x-pack/plugins/security_solution/scripts/quickstart/modules/mappings/index.ts b/x-pack/plugins/security_solution/scripts/quickstart/modules/mappings/index.ts new file mode 100644 index 0000000000000..4448d0cee6897 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/quickstart/modules/mappings/index.ts @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { range } from 'lodash'; +import type { + IndicesIndexSettings, + MappingProperty, + MappingTypeMapping, +} from '@elastic/elasticsearch/lib/api/types'; +import { mappingFromFieldMap } from '@kbn/alerting-plugin/common'; +import { ecsFieldMap } from '@kbn/alerts-as-data-utils'; + +export const getEcsMapping = () => mappingFromFieldMap(ecsFieldMap); + +export interface GenerateLargeMappingPropertiesProps { + size: number; + fieldNameGenerator?: (idx: number) => string; + fieldType?: MappingProperty['type']; +} + +/** + * Generates a large number of field mappings. + * @param size Number of fields to generate + * @param fieldNameGenerator Optional function to determine how the fields should be named - defaults to `field_1`, `field_2`, etc. Dot notation can be + * used to nest fields, e.g. myField.subfield_1, myField.subfield_2, etc. + * @param fieldType The type of ES field to generate + * @returns An object ready to be inserted into the `properties` of an ES mapping object + */ +export const generateLargeMappingProperties = ({ + size, + fieldNameGenerator = (idx: number) => `field_${idx}`, + fieldType = 'keyword', +}: GenerateLargeMappingPropertiesProps): Record => { + const properties: Record = {}; + range(size).forEach((i) => { + properties[fieldNameGenerator(i)] = { type: fieldType } as MappingProperty; // Cast is needed here because TS can't seem to figure out this type correctly + }); + return properties; +}; + +/** + * Simple wrapper around `generateLargeMappingProperties` to build a complete ES mapping object instead of just the core `properties`. See + * generateLargeMappingProperties for details. + * @returns A complete ES mapping object + */ +export const generateLargeMapping = ( + props: GenerateLargeMappingPropertiesProps +): MappingTypeMapping => { + return { properties: generateLargeMappingProperties(props) }; +}; + +/** + * If you're generating a large mapping (more than 1k fields), you'll need to also set this index setting or else you'll see the following error: + * Root causes: + illegal_argument_exception: Limit of total fields [1000] has been exceeded + */ +export const getSettings: ({ maxFields }: { maxFields: number }) => IndicesIndexSettings = ({ + maxFields, +}: { + maxFields: number; +}) => ({ + 'index.mapping.total_fields.limit': maxFields, +}); + +/** + * Injects additional fields into a mapping. Useful for adding additional fields to the standard ECS mapping. + * @param mapping + * @param properties + * @returns A new mapping combining the original mapping and new properties. + */ +export const addPropertiesToMapping = ( + mapping: MappingTypeMapping, + properties: Record +): MappingTypeMapping => { + return { + ...mapping, + properties: { + ...mapping.properties, + ...properties, + }, + }; +}; diff --git a/x-pack/plugins/security_solution/scripts/quickstart/modules/rules/index.ts b/x-pack/plugins/security_solution/scripts/quickstart/modules/rules/index.ts new file mode 100644 index 0000000000000..ca6ef9dd0ff57 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/quickstart/modules/rules/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { range } from 'lodash'; +import type { RuleCreateProps } from '../../../../common/api/detection_engine'; + +export const duplicateRuleParams = ( + rule: RuleCreateProps, + numCopies: number +): RuleCreateProps[] => { + return range(numCopies).map((idx) => ({ ...rule, name: `${rule.name}_${idx}` })); +}; + +export const getBasicRuleMetadata = () => ({ + name: 'Test rule', + description: 'Test rule', + severity: 'low' as const, + risk_score: 21, +}); diff --git a/x-pack/plugins/security_solution/scripts/quickstart/modules/rules/new_terms/basic_rule.ts b/x-pack/plugins/security_solution/scripts/quickstart/modules/rules/new_terms/basic_rule.ts new file mode 100644 index 0000000000000..e047cc37734de --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/quickstart/modules/rules/new_terms/basic_rule.ts @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Client } from '@elastic/elasticsearch'; +import type { NewTermsRuleCreateProps } from '../../../../../common/api/detection_engine'; +import { getEcsMapping, generateLargeMappingProperties, getSettings } from '../../mappings'; + +export const basicRule: NewTermsRuleCreateProps = { + type: 'new_terms', + description: 'test rule', + name: 'test rule', + risk_score: 20, + severity: 'low', + query: '*', + new_terms_fields: ['host.name'], + history_window_start: 'now-7d', + enabled: false, + index: ['test'], +}; + +/** + * Create test data to trigger the new terms rule above. + */ +export const createData = async (client: Client) => { + const index = 'test-index'; + const ecsMapping = getEcsMapping(); + await client.indices.create({ + index, + mappings: { + ...ecsMapping, + properties: { ...ecsMapping.properties, ...generateLargeMappingProperties({ size: 100 }) }, + }, + settings: getSettings({ maxFields: 5000 }), + }); + + const now = new Date(); + const old = new Date(now); + old.setDate(old.getDate() - 3); + + await client.bulk({ + index, + operations: [ + { index: {} }, + { + '@timestamp': now.toISOString(), + 'host.name': 'host-1', + }, + { index: {} }, + { + '@timestamp': old.toISOString(), + 'host.name': 'host-1', + }, + { index: {} }, + { + '@timestamp': now.toISOString(), + 'host.name': 'host-2', + }, + ], + }); +}; diff --git a/x-pack/plugins/security_solution/scripts/quickstart/modules/rules/query/index.ts b/x-pack/plugins/security_solution/scripts/quickstart/modules/rules/query/index.ts new file mode 100644 index 0000000000000..5ea3e0d91293b --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/quickstart/modules/rules/query/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { QueryRuleCreateProps } from '../../../../../common/api/detection_engine'; + +export const buildBasicQueryRule: () => QueryRuleCreateProps = () => ({ + type: 'query', + query: '*:*', + name: 'Sample Query Rule', + description: 'Sample Query Rule', + severity: 'low', + risk_score: 21, +}); diff --git a/x-pack/plugins/security_solution/scripts/quickstart/modules/rules/threat_match/index.ts b/x-pack/plugins/security_solution/scripts/quickstart/modules/rules/threat_match/index.ts new file mode 100644 index 0000000000000..45333a700f4c2 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/quickstart/modules/rules/threat_match/index.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ThreatMatchRuleCreateProps } from '../../../../../common/api/detection_engine'; + +export const basicThreatMatchRule: ThreatMatchRuleCreateProps = { + type: 'threat_match', + name: 'Basic threat match rule', + description: 'Basic threat match rule', + severity: 'low', + risk_score: 21, + query: '*', + index: ['test'], + threat_query: '*', + threat_index: ['threat_test'], + threat_mapping: [ + { + entries: [ + { + field: 'host.name', + value: 'host.name', + type: 'mapping', + }, + ], + }, + ], +}; + +export const generateThreatMatchRuleData = () => {}; diff --git a/x-pack/plugins/security_solution/scripts/quickstart/modules/rules/utils.ts b/x-pack/plugins/security_solution/scripts/quickstart/modules/rules/utils.ts new file mode 100644 index 0000000000000..1fec1c76430eb --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/quickstart/modules/rules/utils.ts @@ -0,0 +1,6 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ diff --git a/x-pack/plugins/security_solution/scripts/quickstart/run.js b/x-pack/plugins/security_solution/scripts/quickstart/run.js new file mode 100644 index 0000000000000..ba2cb48a06cf9 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/quickstart/run.js @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +require('../../../../../src/setup_node_env'); +require('./scratchpad').cli(); diff --git a/x-pack/plugins/security_solution/scripts/quickstart/scratchpad.ts b/x-pack/plugins/security_solution/scripts/quickstart/scratchpad.ts new file mode 100644 index 0000000000000..b89e6ddad463f --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/quickstart/scratchpad.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 { run } from '@kbn/dev-cli-runner'; +import { Client as ListsClient } from '@kbn/securitysolution-lists-common/api/quickstart_client.gen'; +import { Client as ExceptionsClient } from '@kbn/securitysolution-exceptions-common/api/quickstart_client.gen'; +import { concurrentlyExec } from '@kbn/securitysolution-utils/src/client_concurrency'; +import { HORIZONTAL_LINE } from '../endpoint/common/constants'; +import { createEsClient, createKbnClient } from '../endpoint/common/stack_services'; +import { createToolingLogger } from '../../common/endpoint/data_loaders/utils'; +import { Client as DetectionsClient } from '../../common/api/quickstart_client.gen'; +import { duplicateRuleParams } from './modules/rules'; +import { basicRule } from './modules/rules/new_terms/basic_rule'; + +export const cli = () => { + run( + async (cliContext) => { + /** + * START Client setup - Generic Kibana Client, ES Client, and Detections/Lists/Exceptions specific clients + */ + createToolingLogger.setDefaultLogLevelFromCliFlags(cliContext.flags); + + const log = cliContext.log; + + const kbnClient = createKbnClient({ + log, + url: cliContext.flags.kibana as string, + username: cliContext.flags.username as string, + password: cliContext.flags.password as string, + apiKey: cliContext.flags.apikey as string, + }); + + const esClient = createEsClient({ + log, + url: cliContext.flags.elasticsearch as string, + username: cliContext.flags.username as string, + password: cliContext.flags.password as string, + apiKey: cliContext.flags.apikey as string, + }); + + const detectionsClient = new DetectionsClient({ kbnClient, log }); + const listsClient = new ListsClient({ kbnClient, log }); + const exceptionsClient = new ExceptionsClient({ kbnClient, log }); + + log.info(`${HORIZONTAL_LINE} + Environment Data Loader +${HORIZONTAL_LINE} +`); + + log.info(`Loading data to: ${kbnClient.resolveUrl('')}`); + + /** + * END Client setup + * START Custom data loader logic + */ + + // Replace this code with whatever you want! + const ruleCopies = duplicateRuleParams(basicRule, 200); + const functions = ruleCopies.map((rule) => () => detectionsClient.createRule({ body: rule })); + await concurrentlyExec(functions); + + listsClient.findLists({ query: {} }); + exceptionsClient.findExceptionLists({ query: {} }); + + esClient.indices.exists({ index: 'test' }); + + /** + * END Custom data loader logic + */ + }, + + // Options + { + description: `Loads data into an environment for testing/development`, + flags: { + string: ['kibana', 'username', 'password', 'apikey'], + default: { + kibana: 'http://127.0.0.1:5601', + elasticsearch: 'http://127.0.0.1:9200', + username: 'elastic', + password: 'changeme', + }, + allowUnexpected: false, + help: ` + --username User name to be used for auth against elasticsearch and + kibana (Default: elastic). + --password User name Password (Default: changeme) + --kibana The url to Kibana (Default: http://127.0.0.1:5601) + --apikey The API key for authentication, overrides username/password + `, + }, + } + ); +}; diff --git a/x-pack/plugins/security_solution/tsconfig.json b/x-pack/plugins/security_solution/tsconfig.json index 7a97f239364c8..6ccd61fd34394 100644 --- a/x-pack/plugins/security_solution/tsconfig.json +++ b/x-pack/plugins/security_solution/tsconfig.json @@ -216,6 +216,8 @@ "@kbn/esql-ast", "@kbn/esql-validation-autocomplete", "@kbn/config", + "@kbn/openapi-common", + "@kbn/securitysolution-lists-common", "@kbn/cbor", "@kbn/zod", "@kbn/cloud-security-posture", From be8526326b691d0dd0a8e6cb5384d5c19f027ad9 Mon Sep 17 00:00:00 2001 From: Julia Bardi <90178898+juliaElastic@users.noreply.github.com> Date: Fri, 6 Sep 2024 15:59:27 +0200 Subject: [PATCH 86/99] [Fleet] add additional columns to Agent Logs UI (#192262) ## Summary Closes https://github.com/elastic/kibana/issues/188662 Added `component.id` and `error.message` columns to Agent Details / Logs UI. image --- .../components/agent_logs/agent_logs.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx index 5a9bfecd22144..1cb3fc4461118 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx @@ -50,6 +50,14 @@ const LOG_VIEW_SETTINGS: LogStreamProps['logView'] = { logViewId: 'default', }; +const LOG_VIEW_COLUMNS: LogStreamProps['columns'] = [ + { type: 'timestamp' }, + { field: 'event.dataset', type: 'field' }, + { field: 'component.id', type: 'field' }, + { type: 'message' }, + { field: 'error.message', type: 'field' }, +]; + export interface AgentLogsProps { agent: Agent; agentPolicy?: AgentPolicy; @@ -336,6 +344,7 @@ export const AgentLogsUI: React.FunctionComponent = memo( startTimestamp={dateRangeTimestamps.start} endTimestamp={dateRangeTimestamps.end} query={logStreamQuery} + columns={LOG_VIEW_COLUMNS} />
From 50f8bd6ae9315e44fe6a3f8cf658f21819060c94 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Fri, 6 Sep 2024 10:05:01 -0400 Subject: [PATCH 87/99] [Synthetics] Fix heatmap on monitor detail/history page for very large doc counts (#184177) ## Summary Resolves #180076. ### User-facing updates #### We can now display the heatmap for "very large" document counts ##### This PR _note: The first bucket in this image is empty because that's when my monitor actually started._ image ##### Previously image #### We display appropriate bucketed data This is a weird behavior I only noticed once I had made the new query. For some reason, the chart didn't display all the data it should. This may be related to the initial issue, but even in ranges less than 10k docs I was seeing this behavior. I manually checked this by querying for the bucket spans and ensuring the right number of docs were showing up, which is what I'd expect, because it's highly unlikely there would be a bug like this in the date histogram agg. ##### This PR image ##### Previously image ### Why are you doing this? We have noticed in a few SDH that in cases where users are querying very large document tallies, like a month's worth of data for a monitor that runs every minute, they're not seeing their status heatmap fill up. ~This patch would introduce a multi-stage query mechanism to the pings query endpoint. The PR is in draft state, so the procedure performs the query in this manner all the time, but we may want to add a new param to the endpoint that allows the client to opt into this behavior, or simply cap at the default 10k documents like it does today.~ ~I intend to do a good amount of benchmark testing on this fix locally and in Cloud before I try to merge it. We may also need to explore imposing a hard upper limit on the number of stages we are willing to execute. Right now the query is unbounded and a user could try to query datasets that would result in Kibana retrieving and trying to respond with hundreds of MB of data.~ ### What changed This PR modifies the backend query to rely on a Date Histogram agg, rather than querying the documents directly for this purpose. This agg uses the same interval that the client calculates based on the width of the page. I have kept the existing time bin logic on the client side, and modified the function that builds the data structure to pour the buckets from the histogram into the bins that we serve the chart that the user sees. One drawback is because the buckets are computed by Elasticsearch, we need to make API calls to retrieve more data, whereas on resizes previously, all the data was already present and would get re-bucketed on the client. I think this is acceptable because of the ability to handle larger datasets and given that the query should be very fast still. Additionally: - I have made additional modifications to the frontend logic to prevent unnecessary API calls. Before, the component would always make at least two calls on an initial load. I have also switched from `lodash` `throttle` to `useDebounce` from `react-use`, as this seems to more properly drop intermediate resize events where we would want to skip hitting the API. - I have also changed the render logic. We used to use a default value to build out an initial set of time bins. Unfortunately, with all these changes in place, this results in a weird behavior where we show an empty scale while waiting for data, and the bins then snap to the proper size once the element's width has been determined and the bins get scaled out properly. Instead of this, I skip rendering the chart until the initial width is available via a `ref` applied to the wrapper element. At that point, we send the init width to the hook and use that value for our initial query and bin calculations, so we only ever show bins on the charts that will correspond to the bucketed data we eventually display. - I added a progress indicator to the wrapper element so the user receives an indication that the data is being refreshed. - I added a quiet fetch similar to how the overview page works, so that after an initial render the chart will not have its data dropped until we have new data to replace it with. Along those lines, the hook now watches the page location and if it changes (i.e. to from History to Overview), state management will destroy the heatmap data so we don't have a flicker of other data during a new fetch. ## Testing this PR Unfortunately, to truly test this PR you'd need a monitor with over 10k documents, as that's the criteria specified in the initial issue. I did this by running a monitor over about 10 days on a 1-run-per-minute schedule. You could create a cloud deployment from this PR, or create dummy documents in some way (this can be hard to verify though). I am pretty confident this works and fixes the issue based on my real-world testing. --------- Co-authored-by: shahzad31 --- .../common/constants/synthetics/rest_api.ts | 2 +- .../common/runtime_types/ping/ping.ts | 41 ++---- .../hooks/use_ping_statuses.tsx | 90 ------------ .../monitor_status/monitor_status_data.ts | 40 +++--- .../monitor_status/monitor_status_panel.tsx | 120 ++++++++-------- .../monitor_status/use_monitor_status_data.ts | 135 +++++++++++++----- .../public/apps/synthetics/state/index.ts | 1 - .../synthetics/state/ping_status/actions.ts | 16 --- .../apps/synthetics/state/ping_status/api.ts | 36 ----- .../synthetics/state/ping_status/effects.ts | 23 --- .../synthetics/state/ping_status/index.ts | 64 --------- .../synthetics/state/ping_status/selectors.ts | 29 ---- .../apps/synthetics/state/root_effect.ts | 5 +- .../apps/synthetics/state/root_reducer.ts | 6 +- .../state/status_heatmap/actions.ts | 24 ++++ .../synthetics/state/status_heatmap/api.ts | 35 +++++ .../state/status_heatmap/effects.ts | 34 +++++ .../synthetics/state/status_heatmap/index.ts | 60 ++++++++ .../{ping_status => status_heatmap}/models.ts | 8 +- .../state/status_heatmap/selectors.ts | 14 ++ .../__mocks__/synthetics_store.mock.ts | 36 +---- .../common/pings/monitor_status_heatmap.ts | 88 ++++++++++++ .../synthetics/server/routes/index.ts | 4 +- .../server/routes/pings/get_ping_statuses.ts | 82 ----------- .../synthetics/server/routes/pings/index.ts | 2 +- .../server/routes/pings/ping_heatmap.ts | 43 ++++++ 26 files changed, 509 insertions(+), 529 deletions(-) delete mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_ping_statuses.tsx delete mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/actions.ts delete mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/api.ts delete mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/effects.ts delete mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/index.ts delete mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/selectors.ts create mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/actions.ts create mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/api.ts create mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/effects.ts create mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/index.ts rename x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/{ping_status => status_heatmap}/models.ts (78%) create mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/selectors.ts create mode 100644 x-pack/plugins/observability_solution/synthetics/server/common/pings/monitor_status_heatmap.ts delete mode 100644 x-pack/plugins/observability_solution/synthetics/server/routes/pings/get_ping_statuses.ts create mode 100644 x-pack/plugins/observability_solution/synthetics/server/routes/pings/ping_heatmap.ts diff --git a/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics/rest_api.ts b/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics/rest_api.ts index 23ac30a5ff7b1..ac3e4154b6683 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics/rest_api.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics/rest_api.ts @@ -25,7 +25,7 @@ export enum SYNTHETICS_API_URLS { SYNTHETICS_OVERVIEW = '/internal/synthetics/overview', PINGS = '/internal/synthetics/pings', - PING_STATUSES = '/internal/synthetics/ping_statuses', + MONITOR_STATUS_HEATMAP = '/internal/synthetics/ping_heatmap', OVERVIEW_TRENDS = '/internal/synthetics/overview_trends', OVERVIEW_STATUS = `/internal/synthetics/overview_status`, INDEX_SIZE = `/internal/synthetics/index_size`, diff --git a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/ping/ping.ts b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/ping/ping.ts index 2e9e36460c7be..cf06fb899c948 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/ping/ping.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/ping/ping.ts @@ -255,24 +255,6 @@ export const PingStateType = t.type({ export type Ping = t.TypeOf; export type PingState = t.TypeOf; -export const PingStatusType = t.intersection([ - t.type({ - timestamp: t.string, - docId: t.string, - config_id: t.string, - locationId: t.string, - summary: t.partial({ - down: t.number, - up: t.number, - }), - }), - t.partial({ - error: PingErrorType, - }), -]); - -export type PingStatus = t.TypeOf; - export const PingsResponseType = t.type({ total: t.number, pings: t.array(PingType), @@ -280,15 +262,6 @@ export const PingsResponseType = t.type({ export type PingsResponse = t.TypeOf; -export const PingStatusesResponseType = t.type({ - total: t.number, - pings: t.array(PingStatusType), - from: t.string, - to: t.string, -}); - -export type PingStatusesResponse = t.TypeOf; - export const GetPingsParamsType = t.intersection([ t.type({ dateRange: DateRangeType, @@ -306,3 +279,17 @@ export const GetPingsParamsType = t.intersection([ ]); export type GetPingsParams = t.TypeOf; + +export const MonitorStatusHeatmapBucketType = t.type({ + doc_count: t.number, + down: t.type({ + value: t.number, + }), + up: t.type({ + value: t.number, + }), + key: t.number, + key_as_string: t.string, +}); + +export type MonitorStatusHeatmapBucket = t.TypeOf; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_ping_statuses.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_ping_statuses.tsx deleted file mode 100644 index cb408678c022c..0000000000000 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_ping_statuses.tsx +++ /dev/null @@ -1,90 +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 { useEffect, useCallback, useRef } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; - -import { ConfigKey, PingStatus } from '../../../../../../common/runtime_types'; -import { - getMonitorPingStatusesAction, - selectIsMonitorStatusesLoading, - selectPingStatusesForMonitorAndLocationAsc, -} from '../../../state'; - -import { useSelectedMonitor } from './use_selected_monitor'; -import { useSelectedLocation } from './use_selected_location'; - -export const usePingStatuses = ({ - from, - to, - size, - monitorInterval, - lastRefresh, -}: { - from: number; - to: number; - size: number; - monitorInterval: number; - lastRefresh: number; -}) => { - const { monitor } = useSelectedMonitor(); - const location = useSelectedLocation(); - - const pingStatusesSelector = useCallback(() => { - return selectPingStatusesForMonitorAndLocationAsc( - monitor?.[ConfigKey.CONFIG_ID] ?? '', - location?.label ?? '' - ); - }, [monitor, location?.label]); - const isLoading = useSelector(selectIsMonitorStatusesLoading); - const pingStatuses = useSelector(pingStatusesSelector()) as PingStatus[]; - const dispatch = useDispatch(); - - const lastCall = useRef({ monitorId: '', locationLabel: '', to: 0, from: 0, lastRefresh: 0 }); - const toDiff = Math.abs(lastCall.current.to - to) / (1000 * 60); - const fromDiff = Math.abs(lastCall.current.from - from) / (1000 * 60); - const lastRefreshDiff = Math.abs(lastCall.current.lastRefresh - lastRefresh) / (1000 * 60); - const isDataChangedEnough = - toDiff >= monitorInterval || - fromDiff >= monitorInterval || - lastRefreshDiff >= 3 || // Minimum monitor interval - monitor?.id !== lastCall.current.monitorId || - location?.label !== lastCall.current.locationLabel; - - useEffect(() => { - if (!isLoading && isDataChangedEnough && monitor?.id && location?.label && from && to && size) { - dispatch( - getMonitorPingStatusesAction.get({ - monitorId: monitor.id, - locationId: location.label, - from, - to, - size, - }) - ); - - lastCall.current = { - monitorId: monitor.id, - locationLabel: location?.label, - to, - from, - lastRefresh, - }; - } - // `isLoading` shouldn't be included in deps - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [dispatch, monitor?.id, location?.label, from, to, size, isDataChangedEnough, lastRefresh]); - - return pingStatuses.filter(({ timestamp }) => { - const timestampN = Number(new Date(timestamp)); - return timestampN >= from && timestampN <= to; - }); -}; - -export const usePingStatusesIsLoading = () => { - return useSelector(selectIsMonitorStatusesLoading) as boolean; -}; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/monitor_status_data.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/monitor_status_data.ts index f588ab242adf9..e5ee43aa04f8d 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/monitor_status_data.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/monitor_status_data.ts @@ -16,7 +16,7 @@ import { COLOR_MODES_STANDARD, } from '@elastic/eui'; import type { BrushEvent } from '@elastic/charts'; -import { PingStatus } from '../../../../../../common/runtime_types'; +import { MonitorStatusHeatmapBucket } from '../../../../../../common/runtime_types'; export const SUCCESS_VIZ_COLOR = VISUALIZATION_COLORS[0]; export const DANGER_VIZ_COLOR = VISUALIZATION_COLORS[VISUALIZATION_COLORS.length - 1]; @@ -114,28 +114,26 @@ export function createTimeBuckets(intervalMinutes: number, from: number, to: num export function createStatusTimeBins( timeBuckets: MonitorStatusTimeBucket[], - pingStatuses: PingStatus[] + heatmapData: MonitorStatusHeatmapBucket[] ): MonitorStatusTimeBin[] { - let iPingStatus = 0; - return (timeBuckets ?? []).map((bucket) => { - const currentBin: MonitorStatusTimeBin = { - start: bucket.start, - end: bucket.end, - ups: 0, - downs: 0, - value: 0, + return timeBuckets.map(({ start, end }) => { + const { ups, downs } = heatmapData + .filter(({ key }) => key >= start && key <= end) + .reduce( + (acc, cur) => ({ + ups: acc.ups + cur.up.value, + downs: acc.downs + cur.down.value, + }), + { ups: 0, downs: 0 } + ); + + return { + start, + end, + ups, + downs, + value: ups + downs === 0 ? 0 : getStatusEffectiveValue(ups, downs), }; - while ( - iPingStatus < pingStatuses.length && - moment(pingStatuses[iPingStatus].timestamp).valueOf() < bucket.end - ) { - currentBin.ups += pingStatuses[iPingStatus]?.summary.up ?? 0; - currentBin.downs += pingStatuses[iPingStatus]?.summary.down ?? 0; - currentBin.value = getStatusEffectiveValue(currentBin.ups, currentBin.downs); - iPingStatus++; - } - - return currentBin; }); } diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/monitor_status_panel.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/monitor_status_panel.tsx index fc75701098761..cb8da0ea599d6 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/monitor_status_panel.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/monitor_status_panel.tsx @@ -5,12 +5,11 @@ * 2.0. */ -import React, { useMemo } from 'react'; +import React, { useMemo, useRef } from 'react'; -import { EuiPanel, useEuiTheme, EuiResizeObserver, EuiSpacer } from '@elastic/eui'; +import { EuiPanel, useEuiTheme, EuiResizeObserver, EuiSpacer, EuiProgress } from '@elastic/eui'; import { Chart, Settings, Heatmap, ScaleType, Tooltip, LEGACY_LIGHT_THEME } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; -import { usePingStatusesIsLoading } from '../hooks/use_ping_statuses'; import { MonitorStatusHeader } from './monitor_status_header'; import { MonitorStatusCellTooltip } from './monitor_status_cell_tooltip'; import { MonitorStatusLegend } from './monitor_status_legend'; @@ -32,9 +31,9 @@ export const MonitorStatusPanel = ({ onBrushed, }: MonitorStatusPanelProps) => { const { euiTheme, colorMode } = useEuiTheme(); - const { timeBins, handleResize, getTimeBinByXValue, xDomain, intervalByWidth } = - useMonitorStatusData({ from, to }); - const isPingStatusesLoading = usePingStatusesIsLoading(); + const initialSizeRef = useRef(null); + const { loading, timeBins, handleResize, getTimeBinByXValue, xDomain, minsPerBin } = + useMonitorStatusData({ from, to, initialSizeRef }); const heatmap = useMemo(() => { return getMonitorStatusChartTheme(euiTheme, brushable); @@ -53,61 +52,66 @@ export const MonitorStatusPanel = ({ - - {(resizeRef) => ( -
- - ( - + handleResize(e)}> + {(resizeRef) => ( +
+ {minsPerBin && ( + + ( + + )} /> - )} - /> - { - onBrushed?.(getBrushData(brushArea)); - }} - locale={i18n.getLocale()} - /> - timeBin.end} - yAccessor={() => 'T'} - valueAccessor={(timeBin) => timeBin.value} - valueFormatter={(d) => d.toFixed(2)} - xAxisLabelFormatter={getXAxisLabelFormatter(intervalByWidth)} - timeZone="UTC" - xScale={{ - type: ScaleType.Time, - interval: { - type: 'calendar', - unit: 'm', - value: intervalByWidth, - }, - }} - /> - -
- )} -
+ { + onBrushed?.(getBrushData(brushArea)); + }} + locale={i18n.getLocale()} + /> + end} + yAccessor={() => 'T'} + valueAccessor={(timeBin) => timeBin.value} + valueFormatter={(d) => d.toFixed(2)} + xAxisLabelFormatter={getXAxisLabelFormatter(minsPerBin)} + timeZone="UTC" + xScale={{ + type: ScaleType.Time, + interval: { + type: 'calendar', + unit: 'm', + value: minsPerBin, + }, + }} + /> +
+ )} +
+ )} +
+
+ {loading && } ); }; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/use_monitor_status_data.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/use_monitor_status_data.ts index 3465c229c65ce..59d807cb3bef8 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/use_monitor_status_data.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/use_monitor_status_data.ts @@ -5,75 +5,134 @@ * 2.0. */ -import { useCallback, useMemo, useState } from 'react'; -import { throttle } from 'lodash'; +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { useDebounce } from 'react-use'; +import { useLocation } from 'react-router-dom'; -import { scheduleToMinutes } from '../../../../../../common/lib/schedule_to_time'; import { useSyntheticsRefreshContext } from '../../../contexts/synthetics_refresh_context'; import { useSelectedMonitor } from '../hooks/use_selected_monitor'; -import { usePingStatuses } from '../hooks/use_ping_statuses'; import { dateToMilli, createTimeBuckets, - createStatusTimeBins, CHART_CELL_WIDTH, indexBinsByEndTime, MonitorStatusPanelProps, + createStatusTimeBins, + MonitorStatusTimeBin, } from './monitor_status_data'; +import { useSelectedLocation } from '../hooks/use_selected_location'; +import { + clearMonitorStatusHeatmapAction, + quietGetMonitorStatusHeatmapAction, + selectHeatmap, +} from '../../../state/status_heatmap'; + +type Props = Pick & { + initialSizeRef?: React.MutableRefObject; +}; -export const useMonitorStatusData = ({ - from, - to, -}: Pick) => { +export const useMonitorStatusData = ({ from, to, initialSizeRef }: Props) => { const { lastRefresh } = useSyntheticsRefreshContext(); const { monitor } = useSelectedMonitor(); - const monitorInterval = Math.max(3, monitor?.schedule ? scheduleToMinutes(monitor?.schedule) : 3); + const location = useSelectedLocation(); + const pageLocation = useLocation(); const fromMillis = dateToMilli(from); const toMillis = dateToMilli(to); const totalMinutes = Math.ceil(toMillis - fromMillis) / (1000 * 60); - const pingStatuses = usePingStatuses({ - from: fromMillis, - to: toMillis, - size: Math.min(10000, Math.ceil((totalMinutes / monitorInterval) * 2)), // Acts as max size between from - to - monitorInterval, + + const [binsAvailableByWidth, setBinsAvailableByWidth] = useState(null); + const [debouncedBinsCount, setDebouncedCount] = useState(null); + + const minsPerBin = + debouncedBinsCount !== null ? Math.floor(totalMinutes / debouncedBinsCount) : null; + + const dispatch = useDispatch(); + const { heatmap: dateHistogram, loading } = useSelector(selectHeatmap); + + useEffect(() => { + if (binsAvailableByWidth === null && initialSizeRef?.current) { + setBinsAvailableByWidth(Math.floor(initialSizeRef?.current?.clientWidth / CHART_CELL_WIDTH)); + } + }, [binsAvailableByWidth, initialSizeRef]); + + useEffect(() => { + if (monitor?.id && location?.label && debouncedBinsCount !== null && minsPerBin !== null) { + dispatch( + quietGetMonitorStatusHeatmapAction.get({ + monitorId: monitor.id, + location: location.label, + from, + to, + interval: minsPerBin, + }) + ); + } + }, [ + dispatch, + from, + to, + minsPerBin, + location?.label, + monitor?.id, lastRefresh, - }); + debouncedBinsCount, + ]); - const [binsAvailableByWidth, setBinsAvailableByWidth] = useState(50); - const intervalByWidth = Math.floor( - Math.max(monitorInterval, totalMinutes / binsAvailableByWidth) - ); + useEffect(() => { + dispatch(clearMonitorStatusHeatmapAction()); + }, [dispatch, pageLocation.pathname]); - // Disabling deps warning as we wanna throttle the callback - // eslint-disable-next-line react-hooks/exhaustive-deps const handleResize = useCallback( - throttle((e: { width: number; height: number }) => { - setBinsAvailableByWidth(Math.floor(e.width / CHART_CELL_WIDTH)); - }, 500), + (e: { width: number; height: number }) => + setBinsAvailableByWidth(Math.floor(e.width / CHART_CELL_WIDTH)), [] ); - const { timeBins, timeBinsByEndTime, xDomain } = useMemo(() => { - const timeBuckets = createTimeBuckets(intervalByWidth, fromMillis, toMillis); - const bins = createStatusTimeBins(timeBuckets, pingStatuses); - const indexedBins = indexBinsByEndTime(bins); + useDebounce( + async () => { + setDebouncedCount(binsAvailableByWidth); + }, + 500, + [binsAvailableByWidth] + ); - const timeDomain = { - min: bins?.[0]?.end ?? fromMillis, - max: bins?.[bins.length - 1]?.end ?? toMillis, + const { timeBins, timeBinMap, xDomain } = useMemo((): { + timeBins: MonitorStatusTimeBin[]; + timeBinMap: Map; + xDomain: { min: number; max: number }; + } => { + if (minsPerBin === null) { + return { + timeBins: [], + timeBinMap: new Map(), + xDomain: { + min: fromMillis, + max: toMillis, + }, + }; + } + const timeBuckets = createTimeBuckets(minsPerBin ?? 50, fromMillis, toMillis); + const bins = createStatusTimeBins(timeBuckets, dateHistogram); + return { + timeBins: bins, + timeBinMap: indexBinsByEndTime(bins), + xDomain: { + min: bins?.[0]?.end ?? fromMillis, + max: bins?.at(-1)?.end ?? toMillis, + }, }; - - return { timeBins: bins, timeBinsByEndTime: indexedBins, xDomain: timeDomain }; - }, [intervalByWidth, pingStatuses, fromMillis, toMillis]); + }, [minsPerBin, fromMillis, toMillis, dateHistogram]); return { - intervalByWidth, + loading, + minsPerBin, timeBins, + getTimeBinByXValue: (xValue: number | undefined) => + xValue === undefined ? undefined : timeBinMap.get(xValue), xDomain, handleResize, - getTimeBinByXValue: (xValue: number | undefined) => - xValue === undefined ? undefined : timeBinsByEndTime.get(xValue), }; }; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/index.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/index.ts index ef319d13740b2..079a68d4444a8 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/index.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/index.ts @@ -17,7 +17,6 @@ export * from './monitor_list'; export * from './monitor_details'; export * from './overview'; export * from './browser_journey'; -export * from './ping_status'; export * from './private_locations'; export type { UpsertMonitorResponse } from './monitor_management/api'; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/actions.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/actions.ts deleted file mode 100644 index f268a5a2c5600..0000000000000 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/actions.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PingStatusesResponse } from '../../../../../common/runtime_types'; -import { createAsyncAction } from '../utils/actions'; - -import { PingStatusActionArgs } from './models'; - -export const getMonitorPingStatusesAction = createAsyncAction< - PingStatusActionArgs, - PingStatusesResponse ->('[PING STATUSES] GET PING STATUSES'); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/api.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/api.ts deleted file mode 100644 index 38930dfb02cb8..0000000000000 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/api.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { SYNTHETICS_API_URLS } from '../../../../../common/constants'; -import { - PingStatusesResponse, - PingStatusesResponseType, -} from '../../../../../common/runtime_types'; -import { apiService } from '../../../../utils/api_service'; - -export const fetchMonitorPingStatuses = async ({ - monitorId, - locationId, - from, - to, - size, -}: { - monitorId: string; - locationId: string; - from: string; - to: string; - size: number; -}): Promise => { - const locations = JSON.stringify([locationId]); - const sort = 'desc'; - - return await apiService.get( - SYNTHETICS_API_URLS.PING_STATUSES, - { monitorId, from, to, locations, sort, size }, - PingStatusesResponseType - ); -}; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/effects.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/effects.ts deleted file mode 100644 index cffae2fb859f5..0000000000000 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/effects.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { takeEvery } from 'redux-saga/effects'; -import { fetchEffectFactory } from '../utils/fetch_effect'; -import { fetchMonitorPingStatuses } from './api'; - -import { getMonitorPingStatusesAction } from './actions'; - -export function* fetchPingStatusesEffect() { - yield takeEvery( - getMonitorPingStatusesAction.get, - fetchEffectFactory( - fetchMonitorPingStatuses, - getMonitorPingStatusesAction.success, - getMonitorPingStatusesAction.fail - ) as ReturnType - ); -} diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/index.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/index.ts deleted file mode 100644 index 350db7cb41177..0000000000000 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/index.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { createReducer } from '@reduxjs/toolkit'; - -import { PingStatus } from '../../../../../common/runtime_types'; - -import { IHttpSerializedFetchError } from '../utils/http_error'; - -import { getMonitorPingStatusesAction } from './actions'; - -export interface PingStatusState { - pingStatuses: { - [monitorId: string]: { - [locationId: string]: { - [timestamp: string]: PingStatus; - }; - }; - }; - loading: boolean; - error: IHttpSerializedFetchError | null; -} - -const initialState: PingStatusState = { - pingStatuses: {}, - loading: false, - error: null, -}; - -export const pingStatusReducer = createReducer(initialState, (builder) => { - builder - .addCase(getMonitorPingStatusesAction.get, (state) => { - state.loading = true; - }) - .addCase(getMonitorPingStatusesAction.success, (state, action) => { - (action.payload.pings ?? []).forEach((ping) => { - // eslint-disable-next-line @typescript-eslint/naming-convention - const { config_id, locationId, timestamp } = ping; - if (!state.pingStatuses[config_id]) { - state.pingStatuses[config_id] = {}; - } - - if (!state.pingStatuses[config_id][locationId]) { - state.pingStatuses[config_id][locationId] = {}; - } - - state.pingStatuses[config_id][locationId][timestamp] = ping; - }); - - state.loading = false; - }) - .addCase(getMonitorPingStatusesAction.fail, (state, action) => { - state.error = action.payload; - state.loading = false; - }); -}); - -export * from './actions'; -export * from './effects'; -export * from './selectors'; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/selectors.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/selectors.ts deleted file mode 100644 index cf3061e0fab33..0000000000000 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/selectors.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { createSelector } from 'reselect'; - -import { PingStatus } from '../../../../../common/runtime_types'; -import { SyntheticsAppState } from '../root_reducer'; - -import { PingStatusState } from '.'; - -type PingSelectorReturnType = (state: SyntheticsAppState) => PingStatus[]; - -const getState = (appState: SyntheticsAppState) => appState.pingStatus; - -export const selectIsMonitorStatusesLoading = createSelector(getState, (state) => state.loading); - -export const selectPingStatusesForMonitorAndLocationAsc = ( - monitorId: string, - locationId: string -): PingSelectorReturnType => - createSelector([(state: SyntheticsAppState) => state.pingStatus], (state: PingStatusState) => { - return Object.values(state?.pingStatuses?.[monitorId]?.[locationId] ?? {}).sort( - (a, b) => Number(new Date(a.timestamp)) - Number(new Date(b.timestamp)) - ); - }); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_effect.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_effect.ts index 424c6fa70eed6..80a3144aef511 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_effect.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_effect.ts @@ -40,8 +40,8 @@ import { } from './overview'; import { fetchServiceLocationsEffect } from './service_locations'; import { browserJourneyEffects, fetchJourneyStepsEffect } from './browser_journey'; -import { fetchPingStatusesEffect } from './ping_status'; import { fetchOverviewStatusEffect } from './overview_status'; +import { fetchMonitorStatusHeatmap, quietFetchMonitorStatusHeatmap } from './status_heatmap'; export const rootEffect = function* root(): Generator { yield all([ @@ -55,7 +55,6 @@ export const rootEffect = function* root(): Generator { fork(browserJourneyEffects), fork(fetchOverviewStatusEffect), fork(fetchNetworkEventsEffect), - fork(fetchPingStatusesEffect), fork(fetchAgentPoliciesEffect), fork(fetchPrivateLocationsEffect), fork(fetchDynamicSettingsEffect), @@ -75,6 +74,8 @@ export const rootEffect = function* root(): Generator { fork(getCertsListEffect), fork(getDefaultAlertingEffect), fork(enableDefaultAlertingSilentlyEffect), + fork(fetchMonitorStatusHeatmap), + fork(quietFetchMonitorStatusHeatmap), fork(fetchOverviewTrendStats), fork(refreshOverviewTrendStats), ]); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_reducer.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_reducer.ts index a17749de498ff..f8ace41e93191 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_reducer.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_reducer.ts @@ -30,12 +30,11 @@ import { monitorListReducer, MonitorListState } from './monitor_list'; import { serviceLocationsReducer, ServiceLocationsState } from './service_locations'; import { monitorOverviewReducer, MonitorOverviewState } from './overview'; import { BrowserJourneyState } from './browser_journey/models'; -import { pingStatusReducer, PingStatusState } from './ping_status'; +import { monitorStatusHeatmapReducer, MonitorStatusHeatmap } from './status_heatmap'; export interface SyntheticsAppState { ui: UiState; settings: SettingsState; - pingStatus: PingStatusState; elasticsearch: QueriesState; monitorList: MonitorListState; overview: MonitorOverviewState; @@ -52,12 +51,12 @@ export interface SyntheticsAppState { serviceLocations: ServiceLocationsState; overviewStatus: OverviewStatusStateReducer; syntheticsEnablement: SyntheticsEnablementState; + monitorStatusHeatmap: MonitorStatusHeatmap; } export const rootReducer = combineReducers({ ui: uiReducer, settings: settingsReducer, - pingStatus: pingStatusReducer, monitorList: monitorListReducer, overview: monitorOverviewReducer, globalParams: globalParamsReducer, @@ -74,4 +73,5 @@ export const rootReducer = combineReducers({ syntheticsEnablement: syntheticsEnablementReducer, certificates: certificatesReducer, certsList: certsListReducer, + monitorStatusHeatmap: monitorStatusHeatmapReducer, }); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/actions.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/actions.ts new file mode 100644 index 0000000000000..f56fe727e7cbb --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/actions.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createAction } from '@reduxjs/toolkit'; +import { MonitorStatusHeatmapBucket } from '../../../../../common/runtime_types'; +import { createAsyncAction } from '../utils/actions'; + +import { MonitorStatusHeatmapActionArgs } from './models'; + +export const getMonitorStatusHeatmapAction = createAsyncAction< + MonitorStatusHeatmapActionArgs, + MonitorStatusHeatmapBucket[] +>('MONITOR STATUS HEATMAP'); + +export const clearMonitorStatusHeatmapAction = createAction('CLEAR MONITOR STATUS HEATMAP'); + +export const quietGetMonitorStatusHeatmapAction = createAsyncAction< + MonitorStatusHeatmapActionArgs, + MonitorStatusHeatmapBucket[] +>('QUIET GET MONITOR STATUS HEATMAP'); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/api.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/api.ts new file mode 100644 index 0000000000000..482e7d3c15939 --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/api.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 { SYNTHETICS_API_URLS } from '../../../../../common/constants'; +import { MonitorStatusHeatmapBucket } from '../../../../../common/runtime_types'; +import { apiService } from '../../../../utils/api_service'; + +export const fetchMonitorStatusHeatmap = async ({ + monitorId, + location, + from, + to, + interval, +}: { + monitorId: string; + location: string; + from: string | number; + to: string | number; + interval: number; +}): Promise => { + const response = await apiService.get<{ + result: MonitorStatusHeatmapBucket[]; + }>(SYNTHETICS_API_URLS.MONITOR_STATUS_HEATMAP, { + monitorId, + location, + from, + to, + interval, + }); + return response.result; +}; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/effects.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/effects.ts new file mode 100644 index 0000000000000..beffc42367e9a --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/effects.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 { takeLatest } from 'redux-saga/effects'; +import { fetchEffectFactory } from '../utils/fetch_effect'; +import { fetchMonitorStatusHeatmap as api } from './api'; + +import { getMonitorStatusHeatmapAction, quietGetMonitorStatusHeatmapAction } from './actions'; + +export function* fetchMonitorStatusHeatmap() { + yield takeLatest( + getMonitorStatusHeatmapAction.get, + fetchEffectFactory( + api, + getMonitorStatusHeatmapAction.success, + getMonitorStatusHeatmapAction.fail + ) as ReturnType + ); +} + +export function* quietFetchMonitorStatusHeatmap() { + yield takeLatest( + quietGetMonitorStatusHeatmapAction.get, + fetchEffectFactory( + api, + getMonitorStatusHeatmapAction.success, + getMonitorStatusHeatmapAction.fail + ) as ReturnType + ); +} diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/index.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/index.ts new file mode 100644 index 0000000000000..29f8a1ba87345 --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/index.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createReducer } from '@reduxjs/toolkit'; + +import { MonitorStatusHeatmapBucket } from '../../../../../common/runtime_types'; + +import { IHttpSerializedFetchError } from '../utils/http_error'; + +import { + clearMonitorStatusHeatmapAction, + getMonitorStatusHeatmapAction, + quietGetMonitorStatusHeatmapAction, +} from './actions'; + +export interface MonitorStatusHeatmap { + heatmap: MonitorStatusHeatmapBucket[]; + loading: boolean; + error: IHttpSerializedFetchError | null; +} + +const initialState: MonitorStatusHeatmap = { + heatmap: [], + loading: false, + error: null, +}; + +export const monitorStatusHeatmapReducer = createReducer(initialState, (builder) => { + builder + .addCase(quietGetMonitorStatusHeatmapAction.success, (state, action) => { + state.heatmap = action.payload; + state.loading = false; + }) + .addCase(quietGetMonitorStatusHeatmapAction.get, (state) => { + state.loading = true; + }) + .addCase(getMonitorStatusHeatmapAction.get, (state) => { + state.loading = true; + state.heatmap = []; + }) + .addCase(getMonitorStatusHeatmapAction.success, (state, action) => { + state.heatmap = action.payload; + state.loading = false; + }) + .addCase(getMonitorStatusHeatmapAction.fail, (state, action) => { + state.error = action.payload; + state.loading = false; + }) + .addCase(clearMonitorStatusHeatmapAction, (state) => { + state.heatmap = []; + }); +}); + +export * from './actions'; +export * from './effects'; +export * from './selectors'; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/models.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/models.ts similarity index 78% rename from x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/models.ts rename to x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/models.ts index bae8ae9acb3fa..fbf5812306511 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/ping_status/models.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/models.ts @@ -5,10 +5,10 @@ * 2.0. */ -export interface PingStatusActionArgs { - monitorId: string; - locationId: string; +export interface MonitorStatusHeatmapActionArgs { from: string | number; to: string | number; - size: number; + interval: number; + monitorId: string; + location: string; } diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/selectors.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/selectors.ts new file mode 100644 index 0000000000000..dc28e8473d12d --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/status_heatmap/selectors.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createSelector } from 'reselect'; + +import { SyntheticsAppState } from '../root_reducer'; + +const getState = (appState: SyntheticsAppState) => appState.monitorStatusHeatmap; + +export const selectHeatmap = createSelector(getState, (state) => state); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/utils/testing/__mocks__/synthetics_store.mock.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/utils/testing/__mocks__/synthetics_store.mock.ts index 897be8c4ad970..b861fe36b9b96 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/utils/testing/__mocks__/synthetics_store.mock.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/utils/testing/__mocks__/synthetics_store.mock.ts @@ -119,7 +119,6 @@ export const mockState: SyntheticsAppState = { monitorDetails: getMonitorDetailsMockSlice(), browserJourney: getBrowserJourneyMockSlice(), networkEvents: {}, - pingStatus: getPingStatusesMockSlice(), agentPolicies: { loading: false, error: null, @@ -165,6 +164,11 @@ export const mockState: SyntheticsAppState = { certs: [], }, }, + monitorStatusHeatmap: { + heatmap: [], + loading: false, + error: null, + }, }; function getBrowserJourneyMockSlice() { @@ -491,33 +495,3 @@ function getMonitorDetailsMockSlice() { selectedLocationId: 'us_central', } as MonitorDetailsState; } - -function getPingStatusesMockSlice() { - const monitorDetails = getMonitorDetailsMockSlice(); - - return { - pingStatuses: monitorDetails.pings.data.reduce((acc, cur) => { - const geoName = cur.observer.geo?.name!; - if (!acc[cur.monitor.id]) { - acc[cur.monitor.id] = {}; - } - - if (!acc[cur.monitor.id][geoName]) { - acc[cur.monitor.id][geoName] = {}; - } - - acc[cur.monitor.id][geoName][cur.timestamp] = { - timestamp: cur.timestamp, - error: undefined, - locationId: geoName, - config_id: cur.config_id!, - docId: cur.docId, - summary: cur.summary!, - }; - - return acc; - }, {} as SyntheticsAppState['pingStatus']['pingStatuses']), - loading: false, - error: null, - } as SyntheticsAppState['pingStatus']; -} diff --git a/x-pack/plugins/observability_solution/synthetics/server/common/pings/monitor_status_heatmap.ts b/x-pack/plugins/observability_solution/synthetics/server/common/pings/monitor_status_heatmap.ts new file mode 100644 index 0000000000000..cc6015463e9a5 --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/server/common/pings/monitor_status_heatmap.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 { SyntheticsEsClient } from '../../lib'; + +export async function queryMonitorHeatmap({ + syntheticsEsClient, + from, + to, + monitorId, + location, + intervalInMinutes, +}: { + syntheticsEsClient: SyntheticsEsClient; + from: number | string; + to: number | string; + monitorId: string; + location: string; + intervalInMinutes: number; +}) { + return syntheticsEsClient.search({ + body: { + size: 0, + query: { + bool: { + filter: [ + { + exists: { + field: 'summary', + }, + }, + { + range: { + '@timestamp': { + gte: from, + lte: to, + }, + }, + }, + { + term: { + 'monitor.id': monitorId, + }, + }, + { + term: { + 'observer.geo.name': location, + }, + }, + ], + }, + }, + sort: [ + { + '@timestamp': { + order: 'desc', + }, + }, + ], + _source: false, + fields: ['@timestamp', 'config_id', 'summary.*', 'error.*', 'observer.geo.name'], + aggs: { + heatmap: { + date_histogram: { + field: '@timestamp', + fixed_interval: `${intervalInMinutes}m`, + }, + aggs: { + up: { + sum: { + field: 'summary.up', + }, + }, + down: { + sum: { + field: 'summary.down', + }, + }, + }, + }, + }, + }, + }); +} diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/index.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/index.ts index ba3bc0b443fb9..8e62964c2d833 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/index.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/index.ts @@ -46,7 +46,7 @@ import { installIndexTemplatesRoute } from './synthetics_service/install_index_t import { editSyntheticsMonitorRoute } from './monitor_cruds/edit_monitor'; import { addSyntheticsMonitorRoute } from './monitor_cruds/add_monitor'; import { addSyntheticsProjectMonitorRoute } from './monitor_cruds/add_monitor_project'; -import { syntheticsGetPingsRoute, syntheticsGetPingStatusesRoute } from './pings'; +import { syntheticsGetPingsRoute, syntheticsGetPingHeatmapRoute } from './pings'; import { createGetCurrentStatusRoute } from './overview_status/overview_status'; import { getHasIntegrationMonitorsRoute } from './fleet/get_has_integration_monitors'; import { enableDefaultAlertingRoute } from './default_alerts/enable_default_alert'; @@ -77,7 +77,6 @@ export const syntheticsAppRestApiRoutes: SyntheticsRestApiRouteFactory[] = [ getServiceAllowedRoute, getAPIKeySyntheticsRoute, syntheticsGetPingsRoute, - syntheticsGetPingStatusesRoute, getHasIntegrationMonitorsRoute, createGetCurrentStatusRoute, getIndexSizesRoute, @@ -102,6 +101,7 @@ export const syntheticsAppRestApiRoutes: SyntheticsRestApiRouteFactory[] = [ getConnectorTypesRoute, createGetDynamicSettingsRoute, createPostDynamicSettingsRoute, + syntheticsGetPingHeatmapRoute, createOverviewTrendsRoute, ]; diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/pings/get_ping_statuses.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/pings/get_ping_statuses.ts deleted file mode 100644 index ffb10e5a931ef..0000000000000 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/pings/get_ping_statuses.ts +++ /dev/null @@ -1,82 +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 { SyntheticsRestApiRouteFactory } from '../types'; -import { SYNTHETICS_API_URLS } from '../../../common/constants'; -import { PingError, PingStatus } from '../../../common/runtime_types'; -import { queryPings } from '../../common/pings/query_pings'; - -import { getPingsRouteQuerySchema } from './get_pings'; - -export const syntheticsGetPingStatusesRoute: SyntheticsRestApiRouteFactory = () => ({ - method: 'GET', - path: SYNTHETICS_API_URLS.PING_STATUSES, - validate: { - query: getPingsRouteQuerySchema, - }, - handler: async ({ syntheticsEsClient, request, response }): Promise => { - const { - from, - to, - index, - monitorId, - status, - sort, - size, - pageIndex, - locations, - excludedLocations, - } = request.query; - - const result = await queryPings({ - syntheticsEsClient, - dateRange: { from, to }, - index, - monitorId, - status, - sort, - size, - pageIndex, - locations: locations ? JSON.parse(locations) : [], - excludedLocations, - fields: ['@timestamp', 'config_id', 'summary.*', 'error.*', 'observer.geo.name'], - fieldsExtractorFn: extractPingStatus, - }); - - return { - ...result, - from, - to, - }; - }, -}); - -function grabPingError(doc: any): PingError | undefined { - const docContainsError = Object.keys(doc?.fields ?? {}).some((key) => key.startsWith('error.')); - if (!docContainsError) { - return undefined; - } - - return { - code: doc.fields['error.code']?.[0], - id: doc.fields['error.id']?.[0], - stack_trace: doc.fields['error.stack_trace']?.[0], - type: doc.fields['error.type']?.[0], - message: doc.fields['error.message']?.[0], - }; -} - -function extractPingStatus(doc: any) { - return { - timestamp: doc.fields['@timestamp']?.[0], - docId: doc._id, - config_id: doc.fields.config_id?.[0], - locationId: doc.fields['observer.geo.name']?.[0], - summary: { up: doc.fields['summary.up']?.[0], down: doc.fields['summary.down']?.[0] }, - error: grabPingError(doc), - } as PingStatus; -} diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/pings/index.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/pings/index.ts index 89fa3194d4dc2..b18a1dcc3a7b8 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/pings/index.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/pings/index.ts @@ -6,4 +6,4 @@ */ export { syntheticsGetPingsRoute } from './get_pings'; -export { syntheticsGetPingStatusesRoute } from './get_ping_statuses'; +export { syntheticsGetPingHeatmapRoute } from './ping_heatmap'; diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/pings/ping_heatmap.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/pings/ping_heatmap.ts new file mode 100644 index 0000000000000..a7eb44967c81c --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/pings/ping_heatmap.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; +import { MonitorStatusHeatmapBucket } from '../../../common/runtime_types'; +import { SYNTHETICS_API_URLS } from '../../../common/constants'; +import { queryMonitorHeatmap } from '../../common/pings/monitor_status_heatmap'; +import { SyntheticsRestApiRouteFactory } from '../types'; + +export const syntheticsGetPingHeatmapRoute: SyntheticsRestApiRouteFactory = () => ({ + method: 'GET', + path: SYNTHETICS_API_URLS.MONITOR_STATUS_HEATMAP, + validate: { + query: schema.object({ + from: schema.maybe(schema.oneOf([schema.number(), schema.string()])), + to: schema.maybe(schema.oneOf([schema.number(), schema.string()])), + interval: schema.number(), + monitorId: schema.string(), + location: schema.string(), + }), + }, + handler: async ({ + syntheticsEsClient, + request, + }): Promise => { + const { from, to, interval: intervalInMinutes, monitorId, location } = request.query; + + const result = await queryMonitorHeatmap({ + syntheticsEsClient, + from, + to, + monitorId, + location, + intervalInMinutes, + }); + + return result.body.aggregations?.heatmap?.buckets as MonitorStatusHeatmapBucket[]; + }, +}); From c8ecc317609f08eb04e55079ee7441e6a753cf91 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Fri, 6 Sep 2024 17:20:10 +0300 Subject: [PATCH 88/99] [Discover][UnifiedDataTable] Fix Display settings popover when sample size is not a multiple of 10 (#192152) - Closes https://github.com/elastic/kibana/issues/192147 ## Summary This PR fixes the bug with `EuiRange` usage in Display settings popover. ### Testing Set a random value to `discover:sampleSize` like `9995`. Reload the page and navigate to Discover. Now it should not crash when user presses Display settings button. Screenshot 2024-09-05 at 08 40 46 ### 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 --- ...table_additional_display_settings.test.tsx | 79 +++++++++++++++++++ ...data_table_additional_display_settings.tsx | 17 +++- 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/packages/kbn-unified-data-table/src/components/data_table_additional_display_settings.test.tsx b/packages/kbn-unified-data-table/src/components/data_table_additional_display_settings.test.tsx index 5afe08db07476..1e9c7e802cbd3 100644 --- a/packages/kbn-unified-data-table/src/components/data_table_additional_display_settings.test.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_additional_display_settings.test.tsx @@ -53,6 +53,7 @@ describe('UnifiedDataTableAdditionalDisplaySettings', function () { ); const input = findTestSubject(component, 'unifiedDataTableSampleSizeInput').last(); expect(input.prop('value')).toBe(10); + expect(input.prop('step')).toBe(10); await act(async () => { input.simulate('change', { @@ -176,6 +177,84 @@ describe('UnifiedDataTableAdditionalDisplaySettings', function () { findTestSubject(component, 'unifiedDataTableSampleSizeInput').last().prop('value') ).toBe(validIntegerValue); }); + + it('should not fail if sample size is not step of 10', async () => { + const onChangeSampleSizeMock = jest.fn(); + + const customSampleSize = 9995; + const newSampleSize = 9990; + + const component = mountWithIntl( + + ); + + let input = findTestSubject(component, 'unifiedDataTableSampleSizeInput').last(); + expect(input.prop('value')).toBe(customSampleSize); + expect(input.prop('step')).toBe(1); + + await act(async () => { + input.simulate('change', { + target: { + value: newSampleSize, + }, + }); + }); + + await new Promise((resolve) => setTimeout(resolve, 0)); + component.update(); + + input = findTestSubject(component, 'unifiedDataTableSampleSizeInput').last(); + expect(input.prop('value')).toBe(newSampleSize); + expect(input.prop('step')).toBe(1); + + expect(onChangeSampleSizeMock).toHaveBeenCalledWith(newSampleSize); + }); + + it('should not fail if sample size is less than 10', async () => { + const onChangeSampleSizeMock = jest.fn(); + + const customSampleSize = 5; + const newSampleSize = 10; + + const component = mountWithIntl( + + ); + let input = findTestSubject(component, 'unifiedDataTableSampleSizeInput').last(); + expect(input.prop('value')).toBe(customSampleSize); + expect(input.prop('step')).toBe(1); + + await act(async () => { + input.simulate('change', { + target: { + value: newSampleSize, + }, + }); + }); + + await new Promise((resolve) => setTimeout(resolve, 0)); + component.update(); + + input = findTestSubject(component, 'unifiedDataTableSampleSizeInput').last(); + expect(input.prop('value')).toBe(newSampleSize); + expect(input.prop('step')).toBe(1); + + expect(onChangeSampleSizeMock).toHaveBeenCalledWith(newSampleSize); + }); }); describe('rowHeight', () => { diff --git a/packages/kbn-unified-data-table/src/components/data_table_additional_display_settings.tsx b/packages/kbn-unified-data-table/src/components/data_table_additional_display_settings.tsx index 9b6629d2c960b..86e24aacbad1d 100644 --- a/packages/kbn-unified-data-table/src/components/data_table_additional_display_settings.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_additional_display_settings.tsx @@ -124,6 +124,17 @@ export const UnifiedDataTableAdditionalDisplaySettings: React.FC< } if (onChangeSampleSize) { + let step = minRangeSampleSize === RANGE_MIN_SAMPLE_SIZE ? RANGE_STEP_SAMPLE_SIZE : 1; + + if ( + step > 1 && + ((activeSampleSize && !checkIfValueIsMultipleOfStep(activeSampleSize, step)) || + !checkIfValueIsMultipleOfStep(minRangeSampleSize, step) || + !checkIfValueIsMultipleOfStep(maxAllowedSampleSize, step)) + ) { + step = 1; // Eui is very strict about step, so we need to switch to 1 if the value is not a multiple of the step + } + settings.push( ); }; + +function checkIfValueIsMultipleOfStep(value: number, step: number) { + return value % step === 0; +} From 337e6925a0bfd33cbc622bc0f265bd0fd2ec866f Mon Sep 17 00:00:00 2001 From: Tiago Vila Verde Date: Fri, 6 Sep 2024 16:25:54 +0200 Subject: [PATCH 89/99] [Entity Manager] Exposing stop and start transforms actions in the EntityClient (#192186) This PR exposes two new methods (`startTransforms` and `stopTransforms`) in the EntityClient as proposed [here](https://github.com/elastic/elastic-entity-model/issues/160) This work is also required by the Entity Analytics team: https://github.com/elastic/security-team/issues/10230 In addition, it splits up `stop_and_delete_transforms` into more granular actions, one for stopping and another for deleting. The uninstall function is now responsible for appropriately calling those actions in sequence. --- .../server/lib/entities/delete_transforms.ts | 58 ++++++++++ .../lib/entities/install_entity_definition.ts | 34 +++--- ...start_transform.ts => start_transforms.ts} | 2 +- .../lib/entities/stop_and_delete_transform.ts | 102 ------------------ .../server/lib/entities/stop_transforms.ts | 65 +++++++++++ .../entities/uninstall_entity_definition.ts | 20 ++-- .../lib/entities/upgrade_entity_definition.ts | 4 +- .../server/lib/entity_client.ts | 14 ++- .../server/routes/enablement/enable.ts | 6 +- .../server/routes/entities/reset.ts | 39 ++++--- .../server/routes/entities/update.ts | 5 +- 11 files changed, 185 insertions(+), 164 deletions(-) create mode 100644 x-pack/plugins/observability_solution/entity_manager/server/lib/entities/delete_transforms.ts rename x-pack/plugins/observability_solution/entity_manager/server/lib/entities/{start_transform.ts => start_transforms.ts} (97%) delete mode 100644 x-pack/plugins/observability_solution/entity_manager/server/lib/entities/stop_and_delete_transform.ts create mode 100644 x-pack/plugins/observability_solution/entity_manager/server/lib/entities/stop_transforms.ts diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/delete_transforms.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/delete_transforms.ts new file mode 100644 index 0000000000000..a66c0998c014d --- /dev/null +++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/delete_transforms.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 { ElasticsearchClient, Logger } from '@kbn/core/server'; +import { EntityDefinition } from '@kbn/entities-schema'; + +import { + generateHistoryTransformId, + generateHistoryBackfillTransformId, + generateLatestTransformId, +} from './helpers/generate_component_id'; +import { retryTransientEsErrors } from './helpers/retry'; +import { isBackfillEnabled } from './helpers/is_backfill_enabled'; + +export async function deleteTransforms( + esClient: ElasticsearchClient, + definition: EntityDefinition, + logger: Logger +) { + try { + const historyTransformId = generateHistoryTransformId(definition); + const latestTransformId = generateLatestTransformId(definition); + await retryTransientEsErrors( + () => + esClient.transform.deleteTransform( + { transform_id: historyTransformId, force: true }, + { ignore: [404] } + ), + { logger } + ); + if (isBackfillEnabled(definition)) { + const historyBackfillTransformId = generateHistoryBackfillTransformId(definition); + await retryTransientEsErrors( + () => + esClient.transform.deleteTransform( + { transform_id: historyBackfillTransformId, force: true }, + { ignore: [404] } + ), + { logger } + ); + } + await retryTransientEsErrors( + () => + esClient.transform.deleteTransform( + { transform_id: latestTransformId, force: true }, + { ignore: [404] } + ), + { logger } + ); + } catch (e) { + logger.error(`Cannot delete history transform [${definition.id}]: ${e}`); + throw e; + } +} diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/install_entity_definition.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/install_entity_definition.ts index 7b0b18bc08a57..54e1a4cffcc39 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/install_entity_definition.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/install_entity_definition.ts @@ -32,11 +32,7 @@ import { saveEntityDefinition, updateEntityDefinition, } from './save_entity_definition'; -import { - stopAndDeleteHistoryBackfillTransform, - stopAndDeleteHistoryTransform, - stopAndDeleteLatestTransform, -} from './stop_and_delete_transform'; + import { isBackfillEnabled } from './helpers/is_backfill_enabled'; import { deleteTemplate, upsertTemplate } from '../manage_index_templates'; import { generateEntitiesLatestIndexTemplateConfig } from './templates/entities_latest_template'; @@ -45,6 +41,8 @@ import { EntityIdConflict } from './errors/entity_id_conflict_error'; import { EntityDefinitionNotFound } from './errors/entity_not_found'; import { EntityDefinitionWithState } from './types'; import { mergeEntityDefinitionUpdate } from './helpers/merge_definition_update'; +import { stopTransforms } from './stop_transforms'; +import { deleteTransforms } from './delete_transforms'; export interface InstallDefinitionParams { esClient: ElasticsearchClient; @@ -91,14 +89,7 @@ export async function installEntityDefinition({ return await install({ esClient, soClient, logger, definition: entityDefinition }); } catch (e) { logger.error(`Failed to install entity definition ${definition.id}: ${e}`); - - await Promise.all([ - stopAndDeleteHistoryTransform(esClient, definition, logger), - isBackfillEnabled(definition) - ? stopAndDeleteHistoryBackfillTransform(esClient, definition, logger) - : Promise.resolve(), - stopAndDeleteLatestTransform(esClient, definition, logger), - ]); + await stopAndDeleteTransforms(esClient, definition, logger); await Promise.all([ deleteHistoryIngestPipeline(esClient, definition, logger), @@ -253,13 +244,7 @@ export async function reinstallEntityDefinition({ }); logger.debug(`Deleting transforms for definition ${definition.id} v${definition.version}`); - await Promise.all([ - stopAndDeleteHistoryTransform(esClient, definition, logger), - isBackfillEnabled(definition) - ? stopAndDeleteHistoryBackfillTransform(esClient, definition, logger) - : Promise.resolve(), - stopAndDeleteLatestTransform(esClient, definition, logger), - ]); + await stopAndDeleteTransforms(esClient, definition, logger); return await install({ esClient, @@ -308,3 +293,12 @@ const shouldReinstallBuiltinDefinition = ( return timedOut || outdated || failed || partial; }; + +const stopAndDeleteTransforms = async ( + esClient: ElasticsearchClient, + definition: EntityDefinition, + logger: Logger +) => { + await stopTransforms(esClient, definition, logger); + await deleteTransforms(esClient, definition, logger); +}; diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/start_transform.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/start_transforms.ts similarity index 97% rename from x-pack/plugins/observability_solution/entity_manager/server/lib/entities/start_transform.ts rename to x-pack/plugins/observability_solution/entity_manager/server/lib/entities/start_transforms.ts index 46bb16ff00ae3..ea2ec7adb5ddc 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/start_transform.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/start_transforms.ts @@ -15,7 +15,7 @@ import { import { retryTransientEsErrors } from './helpers/retry'; import { isBackfillEnabled } from './helpers/is_backfill_enabled'; -export async function startTransform( +export async function startTransforms( esClient: ElasticsearchClient, definition: EntityDefinition, logger: Logger diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/stop_and_delete_transform.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/stop_and_delete_transform.ts deleted file mode 100644 index 17ffeb44affc1..0000000000000 --- a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/stop_and_delete_transform.ts +++ /dev/null @@ -1,102 +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 { ElasticsearchClient, Logger } from '@kbn/core/server'; -import { EntityDefinition } from '@kbn/entities-schema'; -import { - generateHistoryBackfillTransformId, - generateHistoryTransformId, - generateLatestTransformId, -} from './helpers/generate_component_id'; -import { retryTransientEsErrors } from './helpers/retry'; - -export async function stopAndDeleteHistoryTransform( - esClient: ElasticsearchClient, - definition: EntityDefinition, - logger: Logger -) { - try { - const historyTransformId = generateHistoryTransformId(definition); - await retryTransientEsErrors( - () => - esClient.transform.stopTransform( - { transform_id: historyTransformId, wait_for_completion: true, force: true }, - { ignore: [409, 404] } - ), - { logger } - ); - await retryTransientEsErrors( - () => - esClient.transform.deleteTransform( - { transform_id: historyTransformId, force: true }, - { ignore: [404] } - ), - { logger } - ); - } catch (e) { - logger.error(`Cannot stop or delete history transform [${definition.id}]: ${e}`); - throw e; - } -} - -export async function stopAndDeleteHistoryBackfillTransform( - esClient: ElasticsearchClient, - definition: EntityDefinition, - logger: Logger -) { - try { - const historyBackfillTransformId = generateHistoryBackfillTransformId(definition); - await retryTransientEsErrors( - () => - esClient.transform.stopTransform( - { transform_id: historyBackfillTransformId, wait_for_completion: true, force: true }, - { ignore: [409, 404] } - ), - { logger } - ); - await retryTransientEsErrors( - () => - esClient.transform.deleteTransform( - { transform_id: historyBackfillTransformId, force: true }, - { ignore: [404] } - ), - { logger } - ); - } catch (e) { - logger.error(`Cannot stop or delete history backfill transform [${definition.id}]: ${e}`); - throw e; - } -} - -export async function stopAndDeleteLatestTransform( - esClient: ElasticsearchClient, - definition: EntityDefinition, - logger: Logger -) { - try { - const latestTransformId = generateLatestTransformId(definition); - await retryTransientEsErrors( - () => - esClient.transform.stopTransform( - { transform_id: latestTransformId, wait_for_completion: true, force: true }, - { ignore: [409, 404] } - ), - { logger } - ); - await retryTransientEsErrors( - () => - esClient.transform.deleteTransform( - { transform_id: latestTransformId, force: true }, - { ignore: [404] } - ), - { logger } - ); - } catch (e) { - logger.error(`Cannot stop or delete latest transform [${definition.id}]`); - throw e; - } -} diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/stop_transforms.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/stop_transforms.ts new file mode 100644 index 0000000000000..98f9ad351e377 --- /dev/null +++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/stop_transforms.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ElasticsearchClient, Logger } from '@kbn/core/server'; +import { EntityDefinition } from '@kbn/entities-schema'; + +import { + generateHistoryTransformId, + generateHistoryBackfillTransformId, + generateLatestTransformId, +} from './helpers/generate_component_id'; +import { retryTransientEsErrors } from './helpers/retry'; + +import { isBackfillEnabled } from './helpers/is_backfill_enabled'; + +export async function stopTransforms( + esClient: ElasticsearchClient, + definition: EntityDefinition, + logger: Logger +) { + try { + const historyTransformId = generateHistoryTransformId(definition); + const latestTransformId = generateLatestTransformId(definition); + + await retryTransientEsErrors( + () => + esClient.transform.stopTransform( + { transform_id: historyTransformId, wait_for_completion: true, force: true }, + { ignore: [409, 404] } + ), + { logger } + ); + + if (isBackfillEnabled(definition)) { + const historyBackfillTransformId = generateHistoryBackfillTransformId(definition); + await retryTransientEsErrors( + () => + esClient.transform.stopTransform( + { + transform_id: historyBackfillTransformId, + wait_for_completion: true, + force: true, + }, + { ignore: [409, 404] } + ), + { logger } + ); + } + await retryTransientEsErrors( + () => + esClient.transform.stopTransform( + { transform_id: latestTransformId, wait_for_completion: true, force: true }, + { ignore: [409, 404] } + ), + { logger } + ); + } catch (e) { + logger.error(`Cannot stop entity transforms [${definition.id}]: ${e}`); + throw e; + } +} diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/uninstall_entity_definition.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/uninstall_entity_definition.ts index 64871084333c3..8bc8efa3870aa 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/uninstall_entity_definition.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/uninstall_entity_definition.ts @@ -13,18 +13,17 @@ import { deleteEntityDefinition } from './delete_entity_definition'; import { deleteIndices } from './delete_index'; import { deleteHistoryIngestPipeline, deleteLatestIngestPipeline } from './delete_ingest_pipeline'; import { findEntityDefinitions } from './find_entity_definition'; -import { - stopAndDeleteHistoryBackfillTransform, - stopAndDeleteHistoryTransform, - stopAndDeleteLatestTransform, -} from './stop_and_delete_transform'; -import { isBackfillEnabled } from './helpers/is_backfill_enabled'; + import { generateHistoryIndexTemplateId, generateLatestIndexTemplateId, } from './helpers/generate_component_id'; import { deleteTemplate } from '../manage_index_templates'; +import { stopTransforms } from './stop_transforms'; + +import { deleteTransforms } from './delete_transforms'; + export async function uninstallEntityDefinition({ definition, esClient, @@ -38,13 +37,8 @@ export async function uninstallEntityDefinition({ logger: Logger; deleteData?: boolean; }) { - await Promise.all([ - stopAndDeleteHistoryTransform(esClient, definition, logger), - stopAndDeleteLatestTransform(esClient, definition, logger), - isBackfillEnabled(definition) - ? stopAndDeleteHistoryBackfillTransform(esClient, definition, logger) - : Promise.resolve(), - ]); + await stopTransforms(esClient, definition, logger); + await deleteTransforms(esClient, definition, logger); await Promise.all([ deleteHistoryIngestPipeline(esClient, definition, logger), diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/upgrade_entity_definition.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/upgrade_entity_definition.ts index aa94160039b04..a4d44cd45ee17 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/upgrade_entity_definition.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/upgrade_entity_definition.ts @@ -7,7 +7,7 @@ import { EntityDefinition } from '@kbn/entities-schema'; import { installBuiltInEntityDefinitions } from './install_entity_definition'; -import { startTransform } from './start_transform'; +import { startTransforms } from './start_transforms'; import { EntityManagerServerSetup } from '../../types'; import { checkIfEntityDiscoveryAPIKeyIsValid, readEntityDiscoveryAPIKey } from '../auth'; import { getClientsFromAPIKey } from '../utils'; @@ -46,7 +46,7 @@ export async function upgradeBuiltInEntityDefinitions({ }); await Promise.all( - upgradedDefinitions.map((definition) => startTransform(esClient, definition, logger)) + upgradedDefinitions.map((definition) => startTransforms(esClient, definition, logger)) ); return { success: true, definitions: upgradedDefinitions }; diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entity_client.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entity_client.ts index 7fd0bb3c5ee18..0503bdf770818 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/lib/entity_client.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entity_client.ts @@ -10,11 +10,13 @@ import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import { Logger } from '@kbn/logging'; import { installEntityDefinition } from './entities/install_entity_definition'; -import { startTransform } from './entities/start_transform'; +import { startTransforms } from './entities/start_transforms'; import { findEntityDefinitions } from './entities/find_entity_definition'; import { uninstallEntityDefinition } from './entities/uninstall_entity_definition'; import { EntityDefinitionNotFound } from './entities/errors/entity_not_found'; +import { stopTransforms } from './entities/stop_transforms'; + export class EntityClient { constructor( private options: { @@ -39,7 +41,7 @@ export class EntityClient { }); if (!installOnly) { - await startTransform(this.options.esClient, definition, this.options.logger); + await startTransforms(this.options.esClient, definition, this.options.logger); } return installedDefinition; @@ -78,4 +80,12 @@ export class EntityClient { return { definitions }; } + + async startEntityDefinition(definition: EntityDefinition) { + return startTransforms(this.options.esClient, definition, this.options.logger); + } + + async stopEntityDefinition(definition: EntityDefinition) { + return stopTransforms(this.options.esClient, definition, this.options.logger); + } } diff --git a/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/enable.ts b/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/enable.ts index a1d37de7c8df2..9814840d20a0b 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/enable.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/routes/enablement/enable.ts @@ -19,10 +19,12 @@ import { } from '../../lib/auth'; import { builtInDefinitions } from '../../lib/entities/built_in'; import { installBuiltInEntityDefinitions } from '../../lib/entities/install_entity_definition'; -import { startTransform } from '../../lib/entities/start_transform'; + import { EntityDiscoveryApiKeyType } from '../../saved_objects'; import { createEntityManagerServerRoute } from '../create_entity_manager_server_route'; +import { startTransforms } from '../../lib/entities/start_transforms'; + /** * @openapi * /internal/entities/managed/enablement: @@ -125,7 +127,7 @@ export const enableEntityDiscoveryRoute = createEntityManagerServerRoute({ if (!params.query.installOnly) { await Promise.all( installedDefinitions.map((installedDefinition) => - startTransform(esClient, installedDefinition, logger) + startTransforms(esClient, installedDefinition, logger) ) ); } diff --git a/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/reset.ts b/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/reset.ts index e6f4d18339a99..a59c38b3acf7c 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/reset.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/reset.ts @@ -7,6 +7,16 @@ import { resetEntityDefinitionParamsSchema } from '@kbn/entities-schema'; import { z } from '@kbn/zod'; + +import { EntitySecurityException } from '../../lib/entities/errors/entity_security_exception'; +import { InvalidTransformError } from '../../lib/entities/errors/invalid_transform_error'; +import { readEntityDefinition } from '../../lib/entities/read_entity_definition'; + +import { + deleteHistoryIngestPipeline, + deleteLatestIngestPipeline, +} from '../../lib/entities/delete_ingest_pipeline'; +import { deleteIndices } from '../../lib/entities/delete_index'; import { createAndInstallHistoryIngestPipeline, createAndInstallLatestIngestPipeline, @@ -16,23 +26,14 @@ import { createAndInstallHistoryTransform, createAndInstallLatestTransform, } from '../../lib/entities/create_and_install_transform'; -import { deleteIndices } from '../../lib/entities/delete_index'; -import { - deleteHistoryIngestPipeline, - deleteLatestIngestPipeline, -} from '../../lib/entities/delete_ingest_pipeline'; +import { startTransforms } from '../../lib/entities/start_transforms'; import { EntityDefinitionNotFound } from '../../lib/entities/errors/entity_not_found'; -import { EntitySecurityException } from '../../lib/entities/errors/entity_security_exception'; -import { InvalidTransformError } from '../../lib/entities/errors/invalid_transform_error'; + import { isBackfillEnabled } from '../../lib/entities/helpers/is_backfill_enabled'; -import { readEntityDefinition } from '../../lib/entities/read_entity_definition'; -import { startTransform } from '../../lib/entities/start_transform'; -import { - stopAndDeleteHistoryBackfillTransform, - stopAndDeleteHistoryTransform, - stopAndDeleteLatestTransform, -} from '../../lib/entities/stop_and_delete_transform'; + import { createEntityManagerServerRoute } from '../create_entity_manager_server_route'; +import { deleteTransforms } from '../../lib/entities/delete_transforms'; +import { stopTransforms } from '../../lib/entities/stop_transforms'; export const resetEntityDefinitionRoute = createEntityManagerServerRoute({ endpoint: 'POST /internal/entities/definition/{id}/_reset', @@ -47,11 +48,9 @@ export const resetEntityDefinitionRoute = createEntityManagerServerRoute({ const definition = await readEntityDefinition(soClient, params.path.id, logger); // Delete the transform and ingest pipeline - await stopAndDeleteHistoryTransform(esClient, definition, logger); - if (isBackfillEnabled(definition)) { - await stopAndDeleteHistoryBackfillTransform(esClient, definition, logger); - } - await stopAndDeleteLatestTransform(esClient, definition, logger); + await stopTransforms(esClient, definition, logger); + await deleteTransforms(esClient, definition, logger); + await deleteHistoryIngestPipeline(esClient, definition, logger); await deleteLatestIngestPipeline(esClient, definition, logger); await deleteIndices(esClient, definition, logger); @@ -64,7 +63,7 @@ export const resetEntityDefinitionRoute = createEntityManagerServerRoute({ await createAndInstallHistoryBackfillTransform(esClient, definition, logger); } await createAndInstallLatestTransform(esClient, definition, logger); - await startTransform(esClient, definition, logger); + await startTransforms(esClient, definition, logger); return response.ok({ body: { acknowledged: true } }); } catch (e) { diff --git a/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/update.ts b/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/update.ts index 99dee233a0e40..9cf72a9298d42 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/update.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/routes/entities/update.ts @@ -13,11 +13,12 @@ import { z } from '@kbn/zod'; import { EntitySecurityException } from '../../lib/entities/errors/entity_security_exception'; import { InvalidTransformError } from '../../lib/entities/errors/invalid_transform_error'; import { findEntityDefinitionById } from '../../lib/entities/find_entity_definition'; +import { startTransforms } from '../../lib/entities/start_transforms'; import { installationInProgress, reinstallEntityDefinition, } from '../../lib/entities/install_entity_definition'; -import { startTransform } from '../../lib/entities/start_transform'; + import { createEntityManagerServerRoute } from '../create_entity_manager_server_route'; /** @@ -104,7 +105,7 @@ export const updateEntityDefinitionRoute = createEntityManagerServerRoute({ }); if (!params.query.installOnly) { - await startTransform(esClient, updatedDefinition, logger); + await startTransforms(esClient, updatedDefinition, logger); } return response.ok({ body: updatedDefinition }); From 904aee8e6cad491e3de1e5de1f8a1e6946653f43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20C=C3=B4t=C3=A9?= Date: Fri, 6 Sep 2024 11:08:51 -0400 Subject: [PATCH 90/99] Task Partitioner improvements (#192261) In this PR, I'm making a few small improvements to the task manager task partitioner. The improvements include: - Making a Kibana node claim against all the partitions when its node has no assigned partitions (and log a warning) - Making the task partitioner skip the cache whenever the previous fetch did not find any partitions - Log an error message whenever the kibana discover service fails the search for active nodes ## To verify **Claiming against all partitions:** 1. Set `xpack.task_manager.claim_strategy: mget` 2. Apply the following diff to your code ``` diff --git a/x-pack/plugins/task_manager/server/lib/assign_pod_partitions.ts b/x-pack/plugins/task_manager/server/lib/assign_pod_partitions.ts index 8639edd0483..d8d2277dbc1 100644 --- a/x-pack/plugins/task_manager/server/lib/assign_pod_partitions.ts +++ b/x-pack/plugins/task_manager/server/lib/assign_pod_partitions.ts @@ -42,10 +42,10 @@ export function assignPodPartitions({ }: AssignPodPartitionsOpts): number[] { const map = getPartitionMap({ kibanasPerPartition, podNames, partitions }); const podPartitions: number[] = []; - for (const partition of Object.keys(map)) { - if (map[Number(partition)].indexOf(podName) !== -1) { - podPartitions.push(Number(partition)); - } - } + // for (const partition of Object.keys(map)) { + // if (map[Number(partition)].indexOf(podName) !== -1) { + // podPartitions.push(Number(partition)); + // } + // } return podPartitions; } diff --git a/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts b/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts index c0193917f08..fac229d41fb 100644 --- a/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts +++ b/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts @@ -367,6 +367,7 @@ async function searchAvailableTasks({ filterDownBy(InactiveTasks), partitions.length ? tasksWithPartitions(partitions) : undefined ); + console.log('queryUnlimitedTasks', JSON.stringify(queryUnlimitedTasks, null, 2)); searches.push({ query: queryUnlimitedTasks, sort, // note: we could optimize this to not sort on priority, for this case @@ -394,6 +395,7 @@ async function searchAvailableTasks({ filterDownBy(InactiveTasks), partitions.length ? tasksWithPartitions(partitions) : undefined ); + console.log('queryLimitedTasks', JSON.stringify(query, null, 2)); searches.push({ query, sort, ``` 3. Startup Elasticsearch and Kibana 4. Notice something like the following logged as a warning ``` Background task node "5b2de169-2785-441b-ae8c-186a1936b17d" has no assigned partitions, claiming against all partitions ```` 5. Observe the queries logged and ensure no filter exists for partitions **Skipping the cache:** 1. Set `xpack.task_manager.claim_strategy: mget` 2. Apply the following diff to your code ``` diff --git a/x-pack/plugins/task_manager/server/lib/task_partitioner.ts b/x-pack/plugins/task_manager/server/lib/task_partitioner.ts index 9e90d459663..8f1d7b312aa 100644 --- a/x-pack/plugins/task_manager/server/lib/task_partitioner.ts +++ b/x-pack/plugins/task_manager/server/lib/task_partitioner.ts @@ -64,20 +64,18 @@ export class TaskPartitioner { // update the pod partitions cache after 10 seconds or when no partitions were previously found if (now - lastUpdated >= CACHE_INTERVAL || this.podPartitions.length === 0) { try { - const allPodNames = await this.getAllPodNames(); - this.podPartitions = assignPodPartitions({ - kibanasPerPartition: this.kibanasPerPartition, - podName: this.podName, - podNames: allPodNames, - partitions: this.allPartitions, - }); + console.log('Loading partitions from Elasticsearch'); + // const allPodNames = await this.getAllPodNames(); + this.podPartitions = []; this.podPartitionsLastUpdated = now; + return this.podPartitions; } catch (error) { this.logger.error(`Failed to load list of active kibana nodes: ${error.message}`); // return the cached value return this.podPartitions; } } + console.log('Loading partitions from cache'); return this.podPartitions; } ``` 3. Startup Elasticsearch and Kibana 4. Notice we only observe `Loading partitions from Elasticsearch` logs and no `Loading partitions from cache` regardless of the 10s cache threshold. **Error logging:** 1. Set `xpack.task_manager.claim_strategy: mget` 2. Apply the following diff to your code ``` diff --git a/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.ts b/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.ts index c532cb755f7..a9314aae88c 100644 --- a/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.ts +++ b/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.ts @@ -91,6 +91,7 @@ export class KibanaDiscoveryService { } public async getActiveKibanaNodes() { + throw new Error('no'); const { saved_objects: activeNodes } = await this.savedObjectsRepository.find({ type: BACKGROUND_TASK_NODE_SO_NAME, ``` 3. Observe the following error messages logged ``` Failed to load list of active kibana nodes: no ``` --- .../server/lib/task_partitioner.test.ts | 30 +++- .../server/lib/task_partitioner.ts | 9 +- x-pack/plugins/task_manager/server/plugin.ts | 1 + .../server/polling_lifecycle.test.ts | 1 + .../server/queries/query_clauses.test.ts | 1 + .../server/queries/query_clauses.ts | 7 +- .../server/queries/task_claiming.test.ts | 1 + .../task_claimers/strategy_mget.test.ts | 167 ++++++++++++++++++ .../server/task_claimers/strategy_mget.ts | 14 +- .../strategy_update_by_query.test.ts | 1 + 10 files changed, 224 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/task_manager/server/lib/task_partitioner.test.ts b/x-pack/plugins/task_manager/server/lib/task_partitioner.test.ts index 891a55a4d2e52..8122b395235dc 100644 --- a/x-pack/plugins/task_manager/server/lib/task_partitioner.test.ts +++ b/x-pack/plugins/task_manager/server/lib/task_partitioner.test.ts @@ -11,6 +11,7 @@ import { createFindSO, } from '../kibana_discovery_service/mock_kibana_discovery_service'; import { CACHE_INTERVAL, TaskPartitioner } from './task_partitioner'; +import { mockLogger } from '../test_utils'; const POD_NAME = 'test-pod'; @@ -21,6 +22,7 @@ describe('getAllPartitions()', () => { podName: POD_NAME, kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, kibanaDiscoveryService: discoveryServiceMock, + logger: mockLogger(), }); expect(taskPartitioner.getAllPartitions()).toEqual([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, @@ -48,6 +50,7 @@ describe('getPodName()', () => { podName: POD_NAME, kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, kibanaDiscoveryService: discoveryServiceMock, + logger: mockLogger(), }); expect(taskPartitioner.getPodName()).toEqual('test-pod'); }); @@ -87,6 +90,7 @@ describe('getPartitions()', () => { podName: POD_NAME, kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, kibanaDiscoveryService: discoveryServiceMock, + logger: mockLogger(), }); expect(await taskPartitioner.getPartitions()).toEqual(expectedPartitions); }); @@ -96,6 +100,7 @@ describe('getPartitions()', () => { podName: POD_NAME, kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, kibanaDiscoveryService: discoveryServiceMock, + logger: mockLogger(), }); const shorterInterval = CACHE_INTERVAL / 2; @@ -110,8 +115,30 @@ describe('getPartitions()', () => { expect(discoveryServiceMock.getActiveKibanaNodes).toHaveBeenCalledTimes(2); }); + test('skips the cache when there are no partitions stored', async () => { + discoveryServiceMock.getActiveKibanaNodes.mockResolvedValue([]); + const taskPartitioner = new TaskPartitioner({ + podName: POD_NAME, + kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, + kibanaDiscoveryService: discoveryServiceMock, + logger: mockLogger(), + }); + + await taskPartitioner.getPartitions(); + + jest.advanceTimersByTime(CACHE_INTERVAL); + await taskPartitioner.getPartitions(); + + jest.advanceTimersByTime(CACHE_INTERVAL); + await taskPartitioner.getPartitions(); + + expect(discoveryServiceMock.getActiveKibanaNodes).toHaveBeenCalledTimes(3); + }); + test('correctly catches the error from the discovery service and returns the cached value', async () => { + const logger = mockLogger(); const taskPartitioner = new TaskPartitioner({ + logger, podName: POD_NAME, kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, kibanaDiscoveryService: discoveryServiceMock, @@ -119,9 +146,10 @@ describe('getPartitions()', () => { await taskPartitioner.getPartitions(); expect(taskPartitioner.getPodPartitions()).toEqual(expectedPartitions); - discoveryServiceMock.getActiveKibanaNodes.mockRejectedValueOnce([]); + discoveryServiceMock.getActiveKibanaNodes.mockRejectedValueOnce(new Error('foo')); jest.advanceTimersByTime(CACHE_INTERVAL); await taskPartitioner.getPartitions(); expect(taskPartitioner.getPodPartitions()).toEqual(expectedPartitions); + expect(logger.error).toHaveBeenCalledWith('Failed to load list of active kibana nodes: foo'); }); }); diff --git a/x-pack/plugins/task_manager/server/lib/task_partitioner.ts b/x-pack/plugins/task_manager/server/lib/task_partitioner.ts index ff1633911f62d..9e90d4596636a 100644 --- a/x-pack/plugins/task_manager/server/lib/task_partitioner.ts +++ b/x-pack/plugins/task_manager/server/lib/task_partitioner.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { Logger } from 'elastic-apm-node'; import { KibanaDiscoveryService } from '../kibana_discovery_service'; import { assignPodPartitions } from './assign_pod_partitions'; @@ -23,11 +24,13 @@ export interface TaskPartitionerConstructorOpts { kibanaDiscoveryService: KibanaDiscoveryService; kibanasPerPartition: number; podName: string; + logger: Logger; } export class TaskPartitioner { private readonly allPartitions: number[]; private readonly podName: string; private readonly kibanasPerPartition: number; + private readonly logger: Logger; private kibanaDiscoveryService: KibanaDiscoveryService; private podPartitions: number[]; private podPartitionsLastUpdated: number; @@ -39,6 +42,7 @@ export class TaskPartitioner { this.kibanaDiscoveryService = opts.kibanaDiscoveryService; this.podPartitions = []; this.podPartitionsLastUpdated = Date.now() - CACHE_INTERVAL; + this.logger = opts.logger; } getAllPartitions(): number[] { @@ -57,8 +61,8 @@ export class TaskPartitioner { const lastUpdated = new Date(this.podPartitionsLastUpdated).getTime(); const now = Date.now(); - // update the pod partitions cache after 10 seconds - if (now - lastUpdated >= CACHE_INTERVAL) { + // update the pod partitions cache after 10 seconds or when no partitions were previously found + if (now - lastUpdated >= CACHE_INTERVAL || this.podPartitions.length === 0) { try { const allPodNames = await this.getAllPodNames(); this.podPartitions = assignPodPartitions({ @@ -69,6 +73,7 @@ export class TaskPartitioner { }); this.podPartitionsLastUpdated = now; } catch (error) { + this.logger.error(`Failed to load list of active kibana nodes: ${error.message}`); // return the cached value return this.podPartitions; } diff --git a/x-pack/plugins/task_manager/server/plugin.ts b/x-pack/plugins/task_manager/server/plugin.ts index a746d8a9c3580..1d2ab4a84580b 100644 --- a/x-pack/plugins/task_manager/server/plugin.ts +++ b/x-pack/plugins/task_manager/server/plugin.ts @@ -317,6 +317,7 @@ export class TaskManagerPlugin }); const taskPartitioner = new TaskPartitioner({ + logger: this.logger, podName: this.taskManagerId!, kibanaDiscoveryService: this.kibanaDiscoveryService, kibanasPerPartition: this.config.kibanas_per_partition, diff --git a/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts b/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts index 7ba68ae1186ae..e0b23c3a4d95e 100644 --- a/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts +++ b/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts @@ -102,6 +102,7 @@ describe('TaskPollingLifecycle', () => { pollIntervalConfiguration$: of(100), executionContext, taskPartitioner: new TaskPartitioner({ + logger: taskManagerLogger, podName: 'test', kibanaDiscoveryService: {} as KibanaDiscoveryService, kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, diff --git a/x-pack/plugins/task_manager/server/queries/query_clauses.test.ts b/x-pack/plugins/task_manager/server/queries/query_clauses.test.ts index 9bb3bc272bde7..704e86084de92 100644 --- a/x-pack/plugins/task_manager/server/queries/query_clauses.test.ts +++ b/x-pack/plugins/task_manager/server/queries/query_clauses.test.ts @@ -28,6 +28,7 @@ describe('matchesClauses', () => { expect( matchesClauses( mustBeAllOf(TaskWithSchedule), + undefined, shouldBeOneOf(RunningTask, IdleTaskWithExpiredRunAt) ) ).toMatchObject({ diff --git a/x-pack/plugins/task_manager/server/queries/query_clauses.ts b/x-pack/plugins/task_manager/server/queries/query_clauses.ts index 3eda79b4292fd..140ae0659d329 100644 --- a/x-pack/plugins/task_manager/server/queries/query_clauses.ts +++ b/x-pack/plugins/task_manager/server/queries/query_clauses.ts @@ -38,9 +38,12 @@ export interface ScriptClause { export type PinnedQuery = Pick; type BoolClause = Pick; -export function matchesClauses(...clauses: BoolClause[]): BoolClause { +export function matchesClauses(...clauses: Array): BoolClause { return { - bool: Object.assign({}, ...clauses.map((clause) => clause.bool)), + bool: Object.assign( + {}, + ...clauses.filter((clause): clause is BoolClause => !!clause).map((clause) => clause.bool) + ), }; } diff --git a/x-pack/plugins/task_manager/server/queries/task_claiming.test.ts b/x-pack/plugins/task_manager/server/queries/task_claiming.test.ts index 903f6601c7b9c..c4b9b6dd5836e 100644 --- a/x-pack/plugins/task_manager/server/queries/task_claiming.test.ts +++ b/x-pack/plugins/task_manager/server/queries/task_claiming.test.ts @@ -27,6 +27,7 @@ jest.mock('../constants', () => ({ const taskManagerLogger = mockLogger(); const taskPartitioner = new TaskPartitioner({ + logger: taskManagerLogger, podName: 'test', kibanaDiscoveryService: {} as KibanaDiscoveryService, kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, diff --git a/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.test.ts b/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.test.ts index 767c84e37ca21..851a221918c3b 100644 --- a/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.test.ts +++ b/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.test.ts @@ -107,6 +107,7 @@ const taskPartitioner = new TaskPartitioner({ podName: 'test', kibanaDiscoveryService: discoveryServiceMock, kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, + logger: taskManagerLogger, }); // needs more tests in the similar to the `strategy_default.test.ts` test suite @@ -1790,6 +1791,172 @@ describe('TaskClaiming', () => { } `); }); + + test(`it shouldn't filter for partitions when the node has no assigned partitions`, async () => { + jest.spyOn(taskPartitioner, 'getPartitions').mockResolvedValue([]); + const taskManagerId = uuidv4(); + const definitions = new TaskTypeDictionary(mockLogger()); + definitions.registerTaskDefinitions({ + foo: { + title: 'foo', + createTaskRunner: jest.fn(), + }, + bar: { + title: 'bar', + createTaskRunner: jest.fn(), + }, + }); + const claimedResults = await testClaimAvailableTasks({ + storeOpts: { + taskManagerId, + definitions, + }, + taskClaimingOpts: {}, + claimingOpts: { + claimOwnershipUntil: new Date(), + }, + }); + const [ + { + args: { + search: [{ query }], + }, + }, + ] = claimedResults; + + expect(taskManagerLogger.warn).toHaveBeenCalledWith( + 'Background task node "test" has no assigned partitions, claiming against all partitions' + ); + expect(query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "must_not": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "must": Object { + "range": Object { + "task.retryAt": Object { + "gt": "now", + }, + }, + }, + "should": Array [ + Object { + "term": Object { + "task.status": "running", + }, + }, + Object { + "term": Object { + "task.status": "claiming", + }, + }, + ], + }, + }, + ], + }, + }, + ], + "must": Array [ + Object { + "bool": Object { + "must": Array [ + Object { + "term": Object { + "task.enabled": true, + }, + }, + ], + }, + }, + Object { + "bool": Object { + "must": Array [ + Object { + "terms": Object { + "task.taskType": Array [ + "foo", + "bar", + ], + }, + }, + ], + }, + }, + Object { + "bool": Object { + "should": Array [ + Object { + "bool": Object { + "must": Array [ + Object { + "term": Object { + "task.status": "idle", + }, + }, + Object { + "range": Object { + "task.runAt": Object { + "lte": "now", + }, + }, + }, + ], + }, + }, + Object { + "bool": Object { + "must": Array [ + Object { + "bool": Object { + "should": Array [ + Object { + "term": Object { + "task.status": "running", + }, + }, + Object { + "term": Object { + "task.status": "claiming", + }, + }, + ], + }, + }, + Object { + "range": Object { + "task.retryAt": Object { + "lte": "now", + }, + }, + }, + ], + }, + }, + ], + }, + }, + Object { + "bool": Object { + "must_not": Array [ + Object { + "term": Object { + "task.status": "unrecognized", + }, + }, + ], + }, + }, + ], + }, + } + `); + }); }); describe('task events', () => { diff --git a/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts b/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts index 260f398571570..c0193917f0889 100644 --- a/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts +++ b/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts @@ -15,7 +15,7 @@ import { SavedObjectsErrorHelpers } from '@kbn/core/server'; -import apm from 'elastic-apm-node'; +import apm, { Logger } from 'elastic-apm-node'; import { Subject, Observable } from 'rxjs'; import { omit } from 'lodash'; @@ -61,6 +61,7 @@ interface OwnershipClaimingOpts { definitions: TaskTypeDictionary; taskMaxAttempts: Record; taskPartitioner: TaskPartitioner; + logger: Logger; } const SIZE_MULTIPLIER_FOR_TASK_FETCH = 4; @@ -125,6 +126,7 @@ async function claimAvailableTasks(opts: TaskClaimerOpts): Promise { const excludedTaskTypes = new Set(getExcludedTaskTypes(definitions, excludedTaskTypePatterns)); const claimPartitions = buildClaimPartitions({ @@ -334,6 +337,11 @@ async function searchAvailableTasks({ definitions, }); const partitions = await taskPartitioner.getPartitions(); + if (partitions.length === 0) { + logger.warn( + `Background task node "${taskPartitioner.getPodName()}" has no assigned partitions, claiming against all partitions` + ); + } const sort: NonNullable = getClaimSort(definitions); const searches: SearchOpts[] = []; @@ -357,7 +365,7 @@ async function searchAvailableTasks({ const queryUnlimitedTasks = matchesClauses( queryForUnlimitedTasks, filterDownBy(InactiveTasks), - tasksWithPartitions(partitions) + partitions.length ? tasksWithPartitions(partitions) : undefined ); searches.push({ query: queryUnlimitedTasks, @@ -384,7 +392,7 @@ async function searchAvailableTasks({ const query = matchesClauses( queryForLimitedTasks, filterDownBy(InactiveTasks), - tasksWithPartitions(partitions) + partitions.length ? tasksWithPartitions(partitions) : undefined ); searches.push({ query, diff --git a/x-pack/plugins/task_manager/server/task_claimers/strategy_update_by_query.test.ts b/x-pack/plugins/task_manager/server/task_claimers/strategy_update_by_query.test.ts index 7744543ea9577..9453bced9f7ba 100644 --- a/x-pack/plugins/task_manager/server/task_claimers/strategy_update_by_query.test.ts +++ b/x-pack/plugins/task_manager/server/task_claimers/strategy_update_by_query.test.ts @@ -45,6 +45,7 @@ jest.mock('../constants', () => ({ const taskManagerLogger = mockLogger(); const taskPartitioner = new TaskPartitioner({ + logger: taskManagerLogger, podName: 'test', kibanaDiscoveryService: {} as KibanaDiscoveryService, kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, From 6d87f5f5e7fafeeee193f74644f1976d98086874 Mon Sep 17 00:00:00 2001 From: florent-leborgne Date: Fri, 6 Sep 2024 17:18:46 +0200 Subject: [PATCH 91/99] [Docs] Refresh dashboards docs (#191129) ## Summary This PR updates the structure of the Dashboards docs and refreshes some outdated parts of the content. More updates will be made in future PRs to refresh screenshots and to refresh the content more in depth. This new structure and edits: - distribute the pages in more user-oriented identified themes, for better findability, scanning, and to ease possible integration of some of these pages into in-app documentation. - are more future proof to evolve along with upcoming features. ~I'll leave this PR as a draft until I resolve some link dependencies coming from other docs sources and check some additional bits of content.~ Preview available on demand on Slack. Closes: https://github.com/elastic/platform-docs-team/issues/408 (I'll create separate issues for remaining items) Closes: https://github.com/elastic/platform-docs-team/issues/413 Closes: https://github.com/elastic/platform-docs-team/issues/418 --- docs/management/advanced-options.asciidoc | 3 +- docs/management/numeral.asciidoc | 2 +- docs/redirects.asciidoc | 11 +- ...-editors.asciidoc => chart-types.asciidoc} | 15 +- .../user/dashboard/create-dashboards.asciidoc | 151 ++++++ .../dashboard/create-visualizations.asciidoc | 306 ++++++++++++ ...idoc => dashboard-best-practices.asciidoc} | 8 +- .../dashboard/dashboard-controls.asciidoc | 136 ++++++ docs/user/dashboard/dashboard.asciidoc | 458 +----------------- ...teractive.asciidoc => drilldowns.asciidoc} | 284 +---------- docs/user/dashboard/find-dashboards.asciidoc | 4 +- .../images/dashboard-export-saved-object.png | Bin 0 -> 169108 bytes .../images/dashboard-filter-editor.png | Bin 0 -> 231601 bytes .../dashboard/images/dashboard-filter-kql.png | Bin 0 -> 29567 bytes .../images/dashboard-full-screen.png | Bin 0 -> 2254735 bytes .../images/dashboard-global-time-range.png | Bin 0 -> 114918 bytes .../images/dashboard-import-saved-object.png | Bin 0 -> 377159 bytes .../dashboard/images/dashboard-overview.png | Bin 0 -> 743193 bytes .../images/dashboard-panel-maximized.png | Bin 0 -> 349844 bytes .../images/dashboard-starred-list.png | Bin 0 -> 130202 bytes .../images/dashboard-usage-count.png | Bin 0 -> 48405 bytes ...board_ecommerceRevenueDashboard_7.15.0.png | Bin 270322 -> 0 bytes .../dashboard_panelFiltersButton_8.7.0.png | Bin 4163 -> 0 bytes .../images/dashboards-field-statistics.png | Bin 0 -> 240811 bytes .../images/esql-icon-edit-visualization.svg | 1 + .../images/esql-icon-save-visualization.svg | 1 + docs/user/dashboard/lens-advanced.asciidoc | 2 +- docs/user/dashboard/links-panel.asciidoc | 65 +++ .../user/dashboard/manage-dashboards.asciidoc | 12 + .../mark-favorite-dashboards.asciidoc | 9 + docs/user/dashboard/share-dashboards.asciidoc | 26 + docs/user/dashboard/tsvb.asciidoc | 2 +- ...create-a-dashboard-of-lens-panels.asciidoc | 2 +- docs/user/dashboard/tutorials.asciidoc | 10 + docs/user/dashboard/use-dashboards.asciidoc | 177 +++++++ docs/user/dashboard/vega.asciidoc | 2 +- .../dashboard/view-dashboard-usage.asciidoc | 7 + packages/kbn-doc-links/src/get_doc_links.ts | 8 +- 38 files changed, 958 insertions(+), 744 deletions(-) rename docs/user/dashboard/{create-panels-with-editors.asciidoc => chart-types.asciidoc} (92%) create mode 100644 docs/user/dashboard/create-dashboards.asciidoc create mode 100644 docs/user/dashboard/create-visualizations.asciidoc rename docs/user/dashboard/{dashboard-troubleshooting.asciidoc => dashboard-best-practices.asciidoc} (85%) create mode 100644 docs/user/dashboard/dashboard-controls.asciidoc rename docs/user/dashboard/{make-dashboards-interactive.asciidoc => drilldowns.asciidoc} (55%) create mode 100644 docs/user/dashboard/images/dashboard-export-saved-object.png create mode 100644 docs/user/dashboard/images/dashboard-filter-editor.png create mode 100644 docs/user/dashboard/images/dashboard-filter-kql.png create mode 100644 docs/user/dashboard/images/dashboard-full-screen.png create mode 100644 docs/user/dashboard/images/dashboard-global-time-range.png create mode 100644 docs/user/dashboard/images/dashboard-import-saved-object.png create mode 100644 docs/user/dashboard/images/dashboard-overview.png create mode 100644 docs/user/dashboard/images/dashboard-panel-maximized.png create mode 100644 docs/user/dashboard/images/dashboard-starred-list.png create mode 100644 docs/user/dashboard/images/dashboard-usage-count.png delete mode 100644 docs/user/dashboard/images/dashboard_ecommerceRevenueDashboard_7.15.0.png delete mode 100644 docs/user/dashboard/images/dashboard_panelFiltersButton_8.7.0.png create mode 100644 docs/user/dashboard/images/dashboards-field-statistics.png create mode 100644 docs/user/dashboard/images/esql-icon-edit-visualization.svg create mode 100644 docs/user/dashboard/images/esql-icon-save-visualization.svg create mode 100644 docs/user/dashboard/links-panel.asciidoc create mode 100644 docs/user/dashboard/manage-dashboards.asciidoc create mode 100644 docs/user/dashboard/mark-favorite-dashboards.asciidoc create mode 100644 docs/user/dashboard/share-dashboards.asciidoc create mode 100644 docs/user/dashboard/tutorials.asciidoc create mode 100644 docs/user/dashboard/use-dashboards.asciidoc create mode 100644 docs/user/dashboard/view-dashboard-usage.asciidoc diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index 3e8cc1e8b109b..de8d4e6cd0996 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -225,7 +225,8 @@ When enabled, provides access to the experimental *Labs* features for *Canvas*. [[labs-dashboard-defer-below-fold]]`labs:dashboard:deferBelowFold`:: When enabled, the panels that appear below the fold are loaded when they become visible on the dashboard. -_Below the fold_ refers to panels that are not immediately visible when you open a dashboard, but become visible as you scroll. For additional information, refer to <>. +_Below the fold_ refers to panels that are not immediately visible when you open a dashboard, but become visible as you scroll. +//For additional information, refer to <>. [[labs-dashboard-enable-ui]]`labs:dashboard:enable_ui`:: When enabled, provides access to the experimental *Labs* features for *Dashboard*. diff --git a/docs/management/numeral.asciidoc b/docs/management/numeral.asciidoc index d6c8fbc9011fc..f8df0dabfcd55 100644 --- a/docs/management/numeral.asciidoc +++ b/docs/management/numeral.asciidoc @@ -10,7 +10,7 @@ Numeral formatting patterns are used in multiple places in {kib}, including: * <> * <> -* <> +* <> * <> The simplest pattern format is `0`, and the default {kib} pattern is `0,0.[000]`. diff --git a/docs/redirects.asciidoc b/docs/redirects.asciidoc index 5ffdbbcf76831..6ed1e8f2eeb87 100644 --- a/docs/redirects.asciidoc +++ b/docs/redirects.asciidoc @@ -439,6 +439,16 @@ For the most up-to-date API details, refer to the This content has moved. Refer to <>. +[role="exclude", id="create-drilldowns"] +== Create drilldowns + +This content has moved. Refer to <>. + +[role="exclude", id="tsvb"] +== Create drilldowns + +This content has moved. Refer to <>. + //// APM redirects //// @@ -1133,4 +1143,3 @@ Refer to {api-kibana}/group/endpoint-cases[cases API]. == Sync {ml} saved objects API Refer to {api-kibana}/group/endpoint-ml[machine learning APIs]. - diff --git a/docs/user/dashboard/create-panels-with-editors.asciidoc b/docs/user/dashboard/chart-types.asciidoc similarity index 92% rename from docs/user/dashboard/create-panels-with-editors.asciidoc rename to docs/user/dashboard/chart-types.asciidoc index d0cf77ef8a469..d7aa18c38eec8 100644 --- a/docs/user/dashboard/create-panels-with-editors.asciidoc +++ b/docs/user/dashboard/chart-types.asciidoc @@ -1,12 +1,7 @@ -[[aggregation-reference]] -== Create panels with editors - -{kib} provides several editors that you can use to create panels of your data. Each editor supports different features and {ref}/search-aggregations.html[{es} aggregations]. To choose the best editor for your data, review the following information. - -[float] [[chart-types]] -=== Supported panel types +== Supported chart types +[[aggregation-reference]] [options="header"] |=== @@ -494,9 +489,3 @@ Pipeline aggregations are dependent on the outputs calculated from other aggrega |=== For information about {es} pipeline aggregations, refer to {ref}/search-aggregations-pipeline.html[Pipeline aggregations]. - -include::lens.asciidoc[] -include::tsvb.asciidoc[] -include::vega.asciidoc[] -include::aggregation-based.asciidoc[] -include::timelion.asciidoc[] diff --git a/docs/user/dashboard/create-dashboards.asciidoc b/docs/user/dashboard/create-dashboards.asciidoc new file mode 100644 index 0000000000000..48fba9a65d3a5 --- /dev/null +++ b/docs/user/dashboard/create-dashboards.asciidoc @@ -0,0 +1,151 @@ +[[create-dashboards]] += Build dashboards + +{kib} offers many ways to build powerful dashboards that will help you visualize and keep track of the most important information contained in your {es} data. + +* Create and assemble visualizations such as charts or maps, and enrich them with helpful legends containing key data. +* Extract and show key indicators and metrics to keep them visible and highlighted at all times. +* Add text, images, and links to help viewers make the most of your dashboard. +* Include additional controls to facilitate filtering and browsing the data. + +[float] +[[dashboard-minimum-requirements]] + +To create or edit dashboards, you first need to: + +* have {ref}/getting-started-index.html[data indexed into {es}] and a <>. A data view is a subset of your {es} data, and allows you to load just the right data when building a visualization or exploring it. ++ +TIP: If you don't have data at hand and still want to explore dashboards, you can import one of the <> available. + +* have sufficient permissions on the **Dashboard** feature. If that's not the case, you might get a read-only indicator. A {kib} administrator can <>. + +//include::dashboard-best-practices.asciidoc[] + +[[create-dashboard]] +== Create a dashboard + +//To make your dashboard experience as good as possible for you and users who will view it, check the <>. + +. Open the *Dashboard* page in {kib}. + +. Select *Create dashboard* to start with an empty dashboard. ++ +When you create a dashboard, you are automatically in edit mode and can make changes to the dashboard. +[[create-panels-with-lens]] +. Add content to the dashboard. You have several options covered in more details in the <>: +** <>. This option is a shortcut to create a chart using **Lens**, the default visualization editor in {kib}. +** <>. Choose one of the available panels to add and configure content to your dashboard. +** **Add from library**. Select existing content that has already been configured and saved to the **Visualize Library**. +** <>. Add controls to help filter the content of your dashboard. + +. Organize your dashboard by <>. +[[add-dashboard-settings]] +. Define the main settings of your dashboard from the *Settings* menu located in the toolbar. +.. Meaningful title, description, and <> allow you to find the dashboard quickly later when browsing your list of dashboard or using the {kib} search bar. +.. Additional display options allow you unify the look and feel of the dashboard's panels: + +*** *Store time with dashboard* — Saves the specified time filter. +*** *Use margins between panels* — Adds a margin of space between each panel. +*** *Show panel titles* — Displays the titles in the panel headers. +*** *Sync color palettes across panels* — Applies the same color palette to all panels on the dashboard. +*** *Sync cursor across panels* — When you hover your cursor over a time series chart or a heatmap, the cursor on all other related dashboard charts automatically appears. +*** *Sync tooltips across panels* — When you hover your cursor over a *Lens* chart, the tooltips on all other related dashboard charts automatically appears. + +.. Click *Apply*. + +. **Save** Save the dashboard. + +[[open-the-dashboard]] +== Edit a dashboard + +. Open the *Dashboard* page in {kib}. + +. Locate the dashboard you want to edit. ++ +TIP: When looking for a specific dashboard, you can filter them by tag or by creator, or search the list based on their name and description. Note that the creator information is only available for dashboards created on or after version 8.14. + +. Click the dashboard *Title* you want to open. + +. Make sure that you are in **Edit** mode to be able to make changes to the dashboard. You can switch between **Edit** and **View** modes from the toolbar. + +. Make the changes that you need to the dashboard: + +** Adjust the dashboard's settings +** <> +** <> +[[save-dashboards]] +. **Save** the dashboard. You can then leave the **Edit** mode and *Switch to view mode*. + + +[[reset-the-dashboard]] +=== Reset dashboard changes + +When editing a dashboard, you can revert any changes you've made since the last save using **Reset dashboards**. + +NOTE: Once changes are saved, you can no longer revert them in one click, and instead have to edit the dashboard manually. + +. In the toolbar, click *Reset*. + +. On the *Reset dashboard* window, click *Reset dashboard*. + +include::dashboard-controls.asciidoc[leveloffset=-1] + +include::drilldowns.asciidoc[leveloffset=-1] + + +[[arrange-panels]] +== Organize dashboard panels + +[[moving-containers]] +[[resizing-containers]] +=== Move and resize panels + +Compare the data in your panels side-by-side, organize panels by priority, resize the panels so they all appear immediately on the dashboard, and more. + +In the toolbar, click *Edit*, then use the following options: + +* To move, click and hold the panel header, then drag to the new location. + +* To resize, click the resize control, then drag to the new dimensions. + +* To maximize to full screen, open the panel menu, then click *More > Maximize panel*. ++ +TIP: If you <> a dashboard while viewing a full screen panel, the generated link will directly open the same panel in full screen mode. + +[[duplicate-panels]] +=== Copy and duplicate panels + +To duplicate a panel and the configured functionality, use the clone and copy panel options. Cloned and copied panels replicate all of the functionality from the original panel, +including renaming, editing, and cloning. + +[float] +[[clone-panels]] +==== Duplicate panels + +Duplicated panels appear next to the original panel, and move the other panels to provide a space on the dashboard. + +. In the toolbar, click *Edit*. + +. Open the panel menu, then select *Duplicate panel*. + +[float] +[[copy-to-dashboard]] +==== Copy panels + +Copy panels from one dashboard to another dashboard. + +. Open the panel menu, then select *More > Copy to dashboard*. + +. On the *Copy to dashboard* window, select the dashboard, then click *Copy and go to dashboard*. + +== Import dashboards + +You can import dashboards from the **Saved Objects** page under **Stack Management**. Refer to <>. + +When importing dashboards, you also import their related objects, such as data views and visualizations. Import options allow you to define how the import should behave with these related objects. + +* **Check for existing objects**: When selected, objects are not imported when another object with the same ID already exists in this space or cluster. For example, if you import a dashboard that uses a data view which already exists, the data view is not imported and the dashboard uses the existing data view instead. You can also chose to select manually which of the imported or the existing objects are kept by selecting **Request action on conflict**. + +* **Create new objects with random IDs**: All related objects are imported and are assigned a new ID to avoid conflicts. + +image:images/dashboard-import-saved-object.png[Import panel] diff --git a/docs/user/dashboard/create-visualizations.asciidoc b/docs/user/dashboard/create-visualizations.asciidoc new file mode 100644 index 0000000000000..1a27471448f5a --- /dev/null +++ b/docs/user/dashboard/create-visualizations.asciidoc @@ -0,0 +1,306 @@ += Panels and visualizations + +{kib} provides many options to create panels with visualizations of your data and add content to your dashboards. From advanced charts, maps, and metrics to plain text and images, multiple types of panels with different capabilities are available. + +Use one of the editors to create visualizations of your data. Each editor offers various capabilities. + +[[panels-editors]] +[cols="3", options="header"] +|=== + +| **Content** | **Panel type** | **Description** + +.5+| Visualizations +| <> +| The default editor for creating powerful <> in {kib} + +| link:{ref}/esql-kibana.html[ES\|QL] +| Create visualizations from ES\|QL queries + +| <> +| Create beautiful displays of your geographical data + +| <> +| Add a field statistics view of your data to your dashboards + +| <> +| Use Vega to create new types of visualizations + +.3+| Annotations and navigation +| <> +| Add context to your dashboard with markdown-based *text* + +| <> +| Personalize your dashboard with custom images + +| <> +| Add links to other dashboards or to external websites + +.4+| Machine Learning and Analytics +| <> +| Display the results from machine learning anomaly detection jobs + +| <> +| Display an anomaly chart from the *Anomaly Explorer* + +| <> +| Display an anomaly chart from the *Single Metric Viewer* + +| <> +| Display a chart to visualize change points in your data + +.3+| Observability +| link:{observability-guide}/slo.html[SLO overview] +| Visualize a selected SLO’s health, including name, current SLI value, target, and status + +| link:{observability-guide}/slo.html[SLO Alerts] +| Visualize one or more SLO alerts, including status, rule name, duration, and reason. In addition, configure and update alerts, or create cases directly from the panel + +| link:{observability-guide}/slo.html[SLO Error Budget] +| Visualize the consumption of your SLO's error budget + +.3+| Legacy +| <> (deprecated) +| Display a table of live streaming logs + +| <> +.2+| While these panel types are still available, we recommend to use <> + +| <> + +|=== + +include::chart-types.asciidoc[] + +[[manage-panels]] +== Manage panels +When creating a panel, you can choose to add it to a dashboard, or to save it to the Visualize Library so it can be added to multiple dashboards later. + +There are also some common options that you can configure on the various types of panels to make a dashboard easier to navigate and analyze. + +[float] +[[save-the-markdown-panel]] +[[save-to-visualize-library]] +=== Save to the Visualize Library + +To use a panel on multiple dashboards, you can save it to the *Visualize Library*. Any updates made to a shared panel is replicated to all dashboards where the panel is added. +//When panels are saved in the *Visualize Library*, image:dashboard/images/visualize-library-icon.png[Visualize Library icon] appears in the panel header. + +If you created the panel from a dashboard: + +. In the editor, click *Save to library*. + +. Enter the *Title* and add any applicable <>. + +. Select *Add to Dashboard after saving* to add the panel to your dashboard at the same time. + +. Click *Save and return*. + +If you created the panel from the *Visualize Library*: + +. In the editor, click *Save*. + +. On the *Save* window, enter the *Title*. + +. Choose one of the following options: + +* To save the panel to a dashboard and the *Visualize Library*, select *Add to library*, add any applicable <>, then click *Save and go to Dashboard*. + +* To save the panel only to the *Visualize Library*, select *None*, add any applicable <>, then click *Save and add to library*. + +[float] +[[save-to-the-dashboard]] +=== Save to the dashboard + +Return to the dashboard and add the panel without specifying the save options or adding the panel to the *Visualize Library*. + +If you created the panel from a dashboard: + +. In the editor, click *Save and return*. + +. Add an optional title to the panel. + +.. In the panel header, click *No Title*. + +.. On the *Panel settings* window, select *Show title*. + +.. Enter the *Title*, then click *Save*. + +If you created the panel from the *Visualize Library*: + +. Click *Save*. + +. On the *Save* window, add a *Title* to name the visualization. + +. Choose one of the following options: + +* If you want to add the panel to an existing dashboard, select *Existing*, select the dashboard from the dropdown, then click *Save and go to Dashboard*. + +* If you want to add the panel to a new dashboard, select *New*, then click *Save and go to Dashboard*. + +To add unsaved dashboard panels to the *Visualize Library*: + +. Open the panel menu, then select *More > Save to library*. + +. Enter the panel title, then click *Save*. + +[[explore-the-underlying-documents]] +=== Link to Discover + +You can add interactions to panels that allow you to open and explore the data in *Discover*. To use the interactions, the panel must use only one data view. + +There are three types of *Discover* interactions you can add to dashboard panels: + +* *Panel interactions* — Opens panel data in *Discover*, including the dashboard-level filters, but not the panel-level filters. ++ +To enable panel interactions, configure <> in kibana.yml. If you are using 7.13.0 and earlier, panel interactions are enabled by default. ++ +To use panel interactions, open the panel menu, then click *Explore underlying data*. + +* *Series data interactions* — Opens the series data in *Discover*. ++ +To enable series data interactions, configure <> in kibana.yml. If you are using 7.13.0 and earlier, data series interactions are enabled by default. ++ +To use series data interactions, click a data series in the panel. + +* *Saved search interactions* — Opens <> data in *Discover*. ++ +To use saved search interactions, open the panel menu, then click *More > View saved search*. + +[[edit-panels]] +=== Edit panels + +To make changes to the panel, use the panel menu options. + +. In the toolbar, click *Edit*. + +. Open the panel menu, then use the following options: + +* *Edit visualization* — Opens the editor so you can make changes to the panel. ++ +To make changes without changing the original version, open the panel menu, then click *More > Unlink from library*. + +* *Convert to Lens* — Opens *TSVB* and aggregation-based visualizations in *Lens*. + +* *Panel settings* — Opens the *Panel settings* window to change the *title*, *description*, and *time range*. + +* *More > Replace panel* — Opens the *Visualize Library* so you can select a new panel to replace the existing panel. + +* *More > Delete from dashboard* — Removes the panel from the dashboard. ++ +If you want to use the panel later, make sure that you save the panel to the *Visualize Library*. + + + +include::lens.asciidoc[leveloffset=-1] + +[[esql-visualizations]] +== ES|QL visualizations + +You can add ES|QL visualizations to a dashboard directly from queries in Discover, or you can start from a dashboard. + +[float] +=== Edit and add from Discover + +In Discover, {ref}/esql-kibana.html[typing ES|QL queries] automatically shows a visualization. The visualization type depends on the content of the query: histogram, bar charts, etc. You can manually make changes to that visualization and edit its type and display options using the +pencil button image:images/esql-icon-edit-visualization.svg[pencil button]. + +You can then **Save** and add it to an existing or a new dashboard using the save button of the visualization image:images/esql-icon-save-visualization.svg[save button]. + +[float] +=== Create from dashboard + +. From your dashboard, select **Add panel**. +. Choose **ES|QL** under **Visualizations**. An ES|QL editor appears and lets you configure your query and its associated visualization. The **Suggestions** panel can help you find alternative ways to configure the visualization. ++ +TIP: Check the link:esql-language.html[ES|QL reference] to get familiar with the syntax and optimize your query. +. When editing your query or its configuration, run the query to update the preview of the visualization. ++ +image:https://images.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blt69dcceb4f1e12bc1/66c752d6aff77d384dc44209/edit-esql-visualization.gif[Previewing an ESQL visualization] +. Select **Apply and close** to save the visualization to the dashboard. + +[[maps-visualizations]] +== Maps + +The Maps editor has extensive documentation. For your reading comfort, we have moved it to <>. + +[[field-statistics-dashboard]] +== Field statistics + +**Field statistics** panels allow to display a table with additional field information in your dashboards, such as document count, values, and distribution. + +. From your dashboard, select **Add panel**. +. Choose **Field statistics** under **Visualizations**. An ES|QL editor appears and lets you configure your query with the fields and information that you want to show. ++ +TIP: Check the link:esql-language.html[ES|QL reference] to get familiar with the syntax and optimize your query. +. When editing your query or its configuration, run the query to update the preview of the visualization. ++ +image:images/dashboards-field-statistics.png[Editing a field statistics dashboard panel] +. Select **Apply and close** to save the visualization to the dashboard. + +include::vega.asciidoc[leveloffset=-1] + +[[add-text]] +== Text panels + +To provide context to your dashboard panels, add *Text* panels that display important information, instructions, images, and more. You create *Text* panels using GitHub-flavored Markdown text. + +. On the dashboard, click image:images/dashboard_createNewTextButton_7.15.0.png[Create New Text button in dashboard toolbar]. + +. In the *Markdown* field, enter the text, then click *Update*. + +For example, when you enter: + +[role="screenshot"] +image::images/markdown_example_1.png[Markdown text with links] + +The following instructions are displayed: + +[role="screenshot"] +image::images/markdown_example_2.png[Panel with markdown link text] + +Or when you enter: + +[role="screenshot"] +image::images/markdown_example_3.png[Markdown text with image file] + +The following image is displayed: + +[role="screenshot"] +image::images/markdown_example_4.png[Panel with markdown image] + +For detailed information about writing on GitHub, click *Help*. + + + +[[add-image]] +== Image panels + +To personalize your dashboards, add your own logos and graphics with the *Image* panel. You can upload images from your computer, select previously uploaded images, or add images from an external link. + +. On the dashboard, click image:images/dashboard_createNewImageButton_8.7.0.png[Create New Image button in dashboard toolbar]. +. Use the editor to add an image. + +[role="screenshot"] +image::images/dashboard_addImageEditor_8.7.0.png[Add image editor] + +To manage your uploaded image files, open the main menu, then click *Stack Management > Kibana > Files*. + + +[WARNING] +============================================================================ +When you export a dashboard, the uploaded image files are not exported. +When importing a dashboard with an image panel, and the image file is unavailable, the image panel displays a `not found` warning. Such panels have to be fixed manually by re-uploading the image using the panel's image editor. +============================================================================ + +include::links-panel.asciidoc[leveloffset=-1] + +[[legacy-editors]] +== Legacy editors + +include::aggregation-based.asciidoc[] + +include::tsvb.asciidoc[] + +include::timelion.asciidoc[] + diff --git a/docs/user/dashboard/dashboard-troubleshooting.asciidoc b/docs/user/dashboard/dashboard-best-practices.asciidoc similarity index 85% rename from docs/user/dashboard/dashboard-troubleshooting.asciidoc rename to docs/user/dashboard/dashboard-best-practices.asciidoc index 7fe1b7c3067b9..8155d29950f09 100644 --- a/docs/user/dashboard/dashboard-troubleshooting.asciidoc +++ b/docs/user/dashboard/dashboard-best-practices.asciidoc @@ -1,5 +1,8 @@ +[[dashboard-best-practices]] +== Dashboard best practices + [[dashboard-troubleshooting]] -== Improve dashboard loading time +=== Optimize dashboard loading time To improve the dashboard loading time, enable *Defer loading panels below the fold* *Lab*, which loads dashboard panels as they become visible on the dashboard. @@ -15,5 +18,4 @@ To enable *Labs*, contact your administrator, or configure the <> — Adds a dropdown that allows to filter data by selecting one or more values. ++ +For example, if you are using the *[Logs] Web Traffic* dashboard from the sample web logs data, you can add an options list for the `machine.os.keyword` field that allows you to display only the logs generated from `osx` and `ios` operating systems. ++ +[role="screenshot"] +image::images/dashboard_controlsOptionsList_8.7.0.png[Options list control for the `machine.os.keyword` field with the `osx` and `ios` options selected] + +* <> — Adds a slider that allows to filter the data within a specified range of values. This type of control only works with numeric fields. ++ +For example, if you are using the *[Logs] Web Traffic* dashboard from the sample web logs data, you can add a range slider for the `hour_of_day` field that allows you to display only the log data from 9:00AM to 5:00PM. ++ +[role="screenshot"] +image::images/dashboard_controlsRangeSlider_8.3.0.png[Range slider control for the `hour_of_day` field with a range of `9` to `17` selected] + +* <> — Adds a time range slider that allows to filter the data within a specified range of time, advance the time range backward and forward by a unit that you can define, and animate your change in data over the specified time range. ++ +For example, you are using the *[Logs] Web Traffic* dashboard from the sample web logs data, and the global time filter is *Last 7 days*. When you add the time slider, you can click the previous and next buttons to advance the time range backward or forward, and click the play button to watch how the data changes over the last 7 days. +[role="screenshot"] +image::images/dashboard_timeSliderControl_8.7.0.gif[Time slider control for the the Last 7 days] + +[float] +[[create-and-add-options-list-and-range-slider-controls]] +==== Create and add Options list and Range slider controls + +To add interactive Options list and Range slider controls, create the controls, then add them to your dashboard. + +. Open or create a new dashboard. + +. Make sure you are in *Edit* mode, and select *Controls* > *Add control* in the dashboard toolbar. + +. From the *Data view* dropdown, select the data view that contains the field you want to use for the *Control*. + +. In the *Field* list, select the field you want to filter on. + +. Under *Control type*, select whether the control should be an **Options list** or a **Range slider**. ++ +TIP: Range sliders are for Number type fields only. + +. Define how you want the control to appear: + +** *Label*: Overwrite the default field name with a clearer and self-explanatory label. +** *Minimum width*: How much horizontal space does the control occupies. The final width can vary depending on the other controls and their own width setting. +** *Expand width to fit available space*: Expand the width of the control to fit the available horizontal space on the dashboard. + +. Specify the additional settings: + +* For option lists: + +** Define whether users can select multiple values to filter with the control, or only one. +** For option list controls on _string_ and _IP address_ type fields, you can define how the control's embedded search should behave: + +*** **Prefix**: Show options that _start with_ the entered value. +*** **Contains**: Show options that _contain_ the entered value. This setting option is only available for _string_ type fields. Results can take longer to show with this option. +*** **Exact**: Show options that are a 100% match with the entered value. ++ +TIP: The search is not case sensitive. For example, searching for `ios` would still retrieve `iOS` if that value exists. + +** *Ignore timeout for results* delays the display of the list of values to when it is fully loaded. This option is useful for large data sets, to avoid missing some available options in case they take longer to load and appear when using the control. + +* For Range sliders, set the step size. The step size determines the number of steps of the slider. The smaller the step size is, the more steps there is in the slider. + +. Click *Save and close*. The control can now be used. + +. Consider the position of the control if you have several controls active on the dashboard. Controls are applied from left to right, which can change the options available depending on their position when the <> setting is enabled. + +. Save the dashboard. + +[float] +[[add-time-slider-controls]] +==== Add time slider controls + +You can add one interactive time slider control to a dashboard. + +. Open or create a new dashboard. + +. In the dashboard toolbar, click *Controls* > *Add time slider control*. + +. The time slider control uses the time range from the global time filter. To change the time range in the time slider control, <>. + +. Save the dashboard. The control can now be used. + + + +[float] +[[configure-controls-settings]] +==== Configure the controls settings + +Several settings that apply to all controls of a same dashboard are available. + +. In the dashboard toolbar, click *Controls*, then select *Settings*. + +. On the *Control settings* flyout, configure the settings: + +* *Label position* — Specify where the control label appears. + +* *Filtering* settings: + +** **Apply global filters to controls** — Define whether controls should ignore or apply any filter specified in the main filter bar of the dashboard. +** **Apply global time range to controls** — Define whether controls should ignore or apply the main time range specified for the dashboard. Note that <> rely on the global time range and don't work properly when this option is disabled. + +* *Selection* settings: + +** *Validate user selections* — When selected, any selected option that results in no data is ignored. +** *Chain controls* — When selected, controls are applied sequentially from left to right, and line by line. Any selected options in one control narrows the available options in the next control. +** **Apply selections automatically** — The dashboard is updated dynamically when options are selected in controls. When this option is disabled, users first need to **Apply** their control selection before they are applied to the dashboard. + +* To remove all controls from the dashboard, click *Delete all*. + +. Click *Save and close* to apply the changes. + +[float] +[[edit-controls]] +==== Edit Options list and Range slider control settings + +Change the settings for the Options list and Range slider controls. + +. Hover over the control you want to edit, then click image:images/dashboard_controlsEditControl_8.3.0.png[The Edit control icon that opens the Edit control flyout]. + +. On the *Edit control* flyout, change the options, then click *Save and close*. + +[float] +[[remove-controls]] +==== Remove controls + +Remove controls from your dashboard. + +. Hover over the control you want to remove, then click image:images/dashboard_controlsRemoveControl_8.3.0.png[The Remove control icon that removes the control from the dashboard]. + +. On the *Delete control?* window, click *Delete*. \ No newline at end of file diff --git a/docs/user/dashboard/dashboard.asciidoc b/docs/user/dashboard/dashboard.asciidoc index d597cf135f396..5ca198c9831af 100644 --- a/docs/user/dashboard/dashboard.asciidoc +++ b/docs/user/dashboard/dashboard.asciidoc @@ -1,458 +1,34 @@ [[dashboard]] -= Dashboard and visualizations += Dashboards [partintro] -- -**_Visualize your data with dashboards._** +Dashboards are the best way to visualize and share insights from your {es} data. -The best way to understand your data is to visualize it. With dashboards, you can turn your data from one or more <> into a collection of panels -that bring clarity to your data, tell a story about your data, and allow you to focus on only the data that's important to you. +// add link to reference of panel types +A **dashboard** is made of one or more **panels** that you can organize as you like. Each panel can display various types of content: _visualizations_ such as charts, tables, metrics, and maps, _static annotations_ like text or images, or even _specialized views_ for Machine Learning or Observability data. [role="screenshot"] -image:images/dashboard_ecommerceRevenueDashboard_7.15.0.png[Example dashboard] +image:images/dashboard-overview.png[Example dashboard] -Panels display your data in charts, tables, maps, and more, which allow you to compare your data side-by-side to identify patterns and connections. Dashboards support several types of panels to display your data, and several options to create panels. +// add link to create section or list of editors +There are several <> in {kib} that let you create and configure different types of visualizations. -[cols="2"] -|=== +// add link to sharing section +At any time, you can <> you've created with your team, in {kib} or outside. -| <> -| Use one of the editors to create visualizations of your data. Each editor varies in capabilities for all levels of analysts. - -| <> -| Create beautiful displays of your geographical data. - -| <> -| Display the results from machine learning anomaly detection jobs. - -| <> -| Display an anomaly chart from the *Anomaly Explorer*. - -| <> -| Display a table of live streaming logs. - -| <> -| Add interactive filters with *Controls* panels. - -| <> -| Add context to your panels with *Text*. - -| <> -| Personalize your dashboard with a custom image. - -|=== - -[float] -[[create-dashboards]] -== Create dashboards - -Dashboards provide you with the space where you add panels of your data. - -[float] -[[dashboard-minimum-requirements]] -=== Minimum requirements - -To create dashboards, you must meet the minimum requirements. - -* If you need to set up {kib}, use https://www.elastic.co/cloud/elasticsearch-service/signup?baymax=docs-body&elektra=docs[our free trial]. - -* Make sure you have {ref}/getting-started-index.html[data indexed into {es}] and a <>. - -* When the read-only indicator appears, you have insufficient privileges -to create or save dashboards, and the options to create and save dashboards are not visible. For more information, -refer to <>. - -[float] -[[open-the-dashboard]] -=== Open the dashboard - -Begin with an empty dashboard, or open an existing dashboard. - -. Open the main menu, then click *Dashboard*. - -. On the *Dashboards* page, choose one of the following options: - -* To start with an empty dashboard, click *Create dashboard*. -+ -When you create a dashboard, you are automatically in edit mode and can make changes to the dashboard. - -* To open an existing dashboard, click the dashboard *Title* you want to open. -+ -TIP: When looking for a specific dashboard, you can filter them by tag or by creator, or search the list based on their name and description. Note that the creator information is only available for dashboards created on or after version 8.14. -+ -When you open an existing dashboard, you are in view mode. To make changes to the dashboard, click *Edit* in the toolbar. - - -[float] -[[create-panels-with-lens]] -=== Create and add panels - -You create panels using the editors, which you can access from the dashboard toolbar or the *Visualize Library*, or add panels that are saved in the *Visualize Library*, or search results from <>. - -To create panels from the dashboard toolbar, use one of the following options: - -* *Create visualization* — Opens the drag-and-drop editor, which is the recommended way to create visualization panels. - -* *Select type* — Opens the menu for all of the editors and panel types. - -To create panels from the *Visualize Library*: - -. Open the main menu, then click *Visualize Library*. - -. Click *Create visualization*, then select an editor. - -To add existing panels from the *Visualize Library*: - -. In the dashboard toolbar, click *Add from library*. - -. Click the panel you want to add to the dashboard, then click *X*. -+ -When a panel contains a saved query, both queries are applied. -+ -When you add search results from *Discover* to dashboards, the results are not aggregated. - -[[tsvb]] - -[float] -[[save-panels]] -=== Save and add panels - -Consider where you want to save and add the panel in {kib}. - -[float] -[[save-to-visualize-library]] -==== Save to the Visualize Library - -To use the panel on other dashboards and *Canvas* workpads, save the panel to the *Visualize Library*. When panels are saved in the *Visualize Library*, image:dashboard/images/visualize-library-icon.png[Visualize Library icon] appears in the panel header. - -If you created the panel from the dashboard: - -. In the editor, click *Save to library*. - -. Enter the *Title* and add any applicable <>. - -. Make sure that *Add to Dashboard after saving* is selected. - -. Click *Save and return*. - -If you created the panel from the *Visualize Library*: - -. In the editor, click *Save*. - -. On the *Save* window, enter the *Title*. - -. Choose one of the following options: - -* To save the panel to a dashboard and the *Visualize Library*, select *Add to library*, add any applicable <>, then click *Save and go to Dashboard*. - -* To save the panel only to the *Visualize Library*, select *None*, add any applicable <>, then click *Save and add to library*. - -[float] -[[save-to-the-dashboard]] -==== Save to the dashboard - -Return to the dashboard and add the panel without specifying the save options or adding the panel to the *Visualize Library*. - -If you created the panel from the dashboard: - -. In the editor, click *Save and return*. - -. Add an optional title to the panel. - -.. In the panel header, click *No Title*. - -.. On the *Panel settings* window, select *Show title*. - -.. Enter the *Title*, then click *Save*. - -If you created the panel from the *Visualize Library*: - -. Click *Save*. - -. On the *Save* window, enter the *Title*. - -. Choose one of the following options: - -* If you want to add the panel to an existing dashboard, select *Existing*, select the dashboard from the dropdown, then click *Save and go to Dashboard*. - -* If you want to add the panel to a new dashboard, select *New*, then click *Save and go to Dashboard*. - -To add unsaved dashboard panels to the *Visualize Library*: - -. Open the panel menu, then select *More > Save to library*. - -. Enter the panel title, then click *Save*. - -[float] -[[add-text]] -== Add context to panels - -To provide context to your dashboard panels, add *Text* panels that display important information, instructions, images, and more. You create *Text* panels using GitHub-flavored Markdown text. - -. On the dashboard, click image:images/dashboard_createNewTextButton_7.15.0.png[Create New Text button in dashboard toolbar]. - -. In the *Markdown* field, enter the text, then click *Update*. - -For example, when you enter: - -[role="screenshot"] -image::images/markdown_example_1.png[Markdown text with links] - -The following instructions are displayed: - -[role="screenshot"] -image::images/markdown_example_2.png[Panel with markdown link text] - -Or when you enter: - -[role="screenshot"] -image::images/markdown_example_3.png[Markdown text with image file] - -The following image is displayed: - -[role="screenshot"] -image::images/markdown_example_4.png[Panel with markdown image] - -For detailed information about writing on GitHub, click *Help*. - -[float] -[[save-the-markdown-panel]] -=== Save and add the panel - -Save the panel to the *Visualize Library* and add it to the dashboard, or add it to the dashboard without saving. - -To save the panel to the *Visualize Library*: - -. Click *Save to library*. - -. Enter the *Title* and add any applicable <>. - -. Make sure that *Add to Dashboard after saving* is selected. - -. Click *Save and return*. - -To save the panel to the dashboard: - -. Click *Save and return*. - -. Add an optional title to the panel. - -.. In the panel header, click *No Title*. - -.. On the *Panel settings* window, select *Show title*. - -.. Enter the *Title*, then click *Save*. - -[float] -[[add-image]] -== Add image panels - -To personalize your dashboards, add your own logos and graphics with the *Image* panel. You can upload images from your computer, select previously uploaded images, or add images from an external link. - -. On the dashboard, click image:images/dashboard_createNewImageButton_8.7.0.png[Create New Image button in dashboard toolbar]. -. Use the editor to add an image. - -[role="screenshot"] -image::images/dashboard_addImageEditor_8.7.0.png[Add image editor] - -To manage your uploaded image files, open the main menu, then click *Stack Management > Kibana > Files*. - - -[WARNING] -============================================================================ -When you export a dashboard, the uploaded image files are not exported. -When importing a dashboard with an image panel, and the image file is unavailable, the image panel displays a `not found` warning. Such panels have to be fixed manually by re-uploading the image using the panel's image editor. -============================================================================ - -[float] -[[arrange-panels]] -[[moving-containers]] -[[resizing-containers]] -== Arrange panels - -Compare the data in your panels side-by-side, organize panels by priority, resize the panels so they all appear immediately on the dashboard, and more. - -In the toolbar, click *Edit*, then use the following options: - -* To move, click and hold the panel header, then drag to the new location. - -* To resize, click the resize control, then drag to the new dimensions. - -* To maximize to fullscreen, open the panel menu, then click *More > Maximize panel*. - -[float] -[[edit-panels]] -== Edit panels - -To make changes to the panel, use the panel menu options. - -. In the toolbar, click *Edit*. - -. Open the panel menu, then use the following options: - -* *Edit visualization* — Opens the editor so you can make changes to the panel. -+ -To make changes without changing the original version, open the panel menu, then click *More > Unlink from library*. - -* *Convert to Lens* — Opens *TSVB* and aggregation-based visualizations in *Lens*. - -* *Panel settings* — Opens the *Panel settings* window to change the *title*, *description*, and *time range*. - -* *More > Replace panel* — Opens the *Visualize Library* so you can select a new panel to replace the existing panel. - -* *More > Delete from dashboard* — Removes the panel from the dashboard. -+ -If you want to use the panel later, make sure that you save the panel to the *Visualize Library*. - -[float] -[[duplicate-panels]] -== Duplicate panels - -To duplicate a panel and the configured functionality, use the clone and copy panel options. Cloned and copied panels replicate all of the functionality from the original panel, -including renaming, editing, and cloning. - -[float] -[[clone-panels]] -=== Clone panels - -Cloned panels appear next to the original panel, and move the other panels to provide a space on the dashboard. - -. In the toolbar, click *Edit*. - -. Open the panel menu, then select *Clone panel*. -+ -When cloned panels are saved in the *Visualize Library*, image:dashboard/images/visualize-library-icon.png[Visualize Library icon] appears in the header. - -[float] -[[copy-to-dashboard]] -=== Copy panels - -Copy panels from one dashboard to another dashboard. - -. Open the panel menu, then select *More > Copy to dashboard*. - -. On the *Copy to dashboard* window, select the dashboard, then click *Copy and go to dashboard*. - -[float] -[[add-dashboard-settings]] -== Add the dashboard settings - -Add the title, tags, design options, and more to the dashboard. - -. In the toolbar, click *Settings*. - -. On the *Dashboard settings* flyout, enter the *Title* and an optional *Description*. - -. Add any applicable <>. - -. Specify the following settings: - -* *Store time with dashboard* — Saves the specified time filter. - -* *Use margins between panels* — Adds a margin of space between each panel. - -* *Show panel titles* — Displays the titles in the panel headers. - -* *Sync color palettes across panels* — Applies the same color palette to all panels on the dashboard. - -* *Sync cursor across panels* — When you hover your cursor over a *Lens*, *TSVB*, aggregation-based, or *Timelion* XY or heatmap chart, the cursor on all other related dashboard charts automatically appears. - -* *Sync tooltips across panels* — When you hover your cursor over a *Lens*, *TSVB*, aggregation-based, or *Timelion* XY chart, the tooltips on all other related dashboard charts automatically appears. - -. Click *Apply*. - -[float] -[[reset-the-dashboard]] -== Reset the dashboard - -To remove any dashboard changes you've made, reset the dashboard to the last saved changes. - -. In the toolbar, click *Reset*. - -. On the *Reset dashboard* window, click *Reset dashboard*. - -[float] -[[save-dashboards]] -== Save dashboards - -When you've finished making changes to the dashboard, save it. - -. In the toolbar, click *Save*. - -. To exit *Edit* mode, click *Switch to view mode*. - -[float] -[[search-or-filter-your-data]] -== Search and filter your data - -{kib} supports several ways to search your data and apply {es} filters. You can combine the filters with any panel -filter to display the data want to you see. - -For more information about {kib} and {es} filters, refer to <>. - -To apply a panel-level time filter: - -. Open the panel menu, then select *More > Panel settings*. - -. Select *Apply a custom time range*. - -. Enter the time range you want to view, then click *Save*. - -To view and edit panel-level filters: - -. On the panel, click image:images/dashboard_panelFiltersButton_8.7.0.png[Panel filters button on panel header]. - -. To edit, click *Edit filters*. - -[float] -[[download-csv]] -== View the panel data and requests - -View the data in visualizations and the requests that collect the data. - -. Open the panel menu, then click *More > Inspect*. - -. View and download the panel data. - -.. Open the *View* dropdown, then click *Data*. - -.. Click *Download CSV*, then select the format type from the dropdown: - -* *Formatted CSV* — Contains human-readable dates and numbers. - -* *Unformatted* — Best used for computer use. -+ -When you download visualization panels with multiple layers, each layer produces a CSV file, and the file names contain the visualization and layer {data-source} names. - -. View the requests that collect the data. - -.. Open the *View* dropdown, then click *Requests*. - -.. From the dropdown, select the requests you want to view. - -.. To view the requests in *Console*, click *Request*, then click *Open in Console*. - -[float] -[[share-the-dashboard]] -== Share dashboards - -To share the dashboard with a larger audience, click *Share* in the toolbar. For detailed information about the sharing options, refer to <>. - -[float] -[[import-dashboards]] -== Export dashboards - -To automate {kib}, you can export dashboards as NDJSON using the {api-kibana}/group/endpoint-saved-objects[Export saved objects API]. It is important to export dashboards with all necessary references. +Some dashboards are created and managed by the system, and are identified as `managed` in your list of of dashboards. This generally happens when you set up an integration to add data. You can't edit managed dashboards directly, but you can duplicate them and edit these duplicates. -- -include::tutorial-create-a-dashboard-of-lens-panels.asciidoc[] -include::lens-advanced.asciidoc[] +include::use-dashboards.asciidoc[leveloffset=+1] + +include::create-dashboards.asciidoc[leveloffset=+1] -include::create-panels-with-editors.asciidoc[] +include::create-visualizations.asciidoc[leveloffset=+1] -include::make-dashboards-interactive.asciidoc[] +include::manage-dashboards.asciidoc[leveloffset=+1] -include::find-dashboards.asciidoc[] +include::share-dashboards.asciidoc[leveloffset=+1] -include::dashboard-troubleshooting.asciidoc[] +include::tutorials.asciidoc[leveloffset=+1] diff --git a/docs/user/dashboard/make-dashboards-interactive.asciidoc b/docs/user/dashboard/drilldowns.asciidoc similarity index 55% rename from docs/user/dashboard/make-dashboards-interactive.asciidoc rename to docs/user/dashboard/drilldowns.asciidoc index e9833d3a542d5..ab4ddee843ba9 100644 --- a/docs/user/dashboard/make-dashboards-interactive.asciidoc +++ b/docs/user/dashboard/drilldowns.asciidoc @@ -1,16 +1,18 @@ [role="xpack"] [[drilldowns]] -== Make dashboards interactive +=== Drilldowns -:frontmatter-description: Add interactive filter and navigation capabilities to your dashboard. -:frontmatter-tags-products: [kibana] -:frontmatter-tags-content-type: [how-to] -:frontmatter-tags-user-goals: [analyze, visualize] +Panels have built-in interactive capabilities that apply filters to the dashboard data. For example, when you drag a time range or click a pie slice, a filter for the time range or pie slice is applied. Drilldowns let you customize the interactive behavior while keeping the context of the interaction. -Add interactive capabilities to your dashboard, such as interactive filter controls, and drilldowns that allow you to navigate to *Discover*, other dashboards, and external websites. +There are three types of drilldowns you can add to dashboards: -// Video is slightly outdated. Left in at request of dev team. -// See https://github.com/elastic/kibana/pull/161090#issuecomment-1620410065 +* *Dashboard* — Navigates you from one dashboard to another dashboard. For example, create a drilldown for a *Lens* panel that navigates you from a summary dashboard to a dashboard with a filter for a specific host name. + +* *URL* — Navigates you from a dashboard to an external website. For example, a website with the specific host name as a parameter. + +* *Discover* — Navigates you from a *Lens* dashboard panel to *Discover*. For example, create a drilldown for a *Lens* visualization that opens the visualization data in *Discover* for further exploration. + +Third-party developers can create drilldowns. To learn how to code drilldowns, refer to {kib-repo}blob/{branch}/x-pack/examples/ui_actions_enhanced_examples[this example plugin]. ++++