From 9cbd597ebb2a3912eb3897142c61b22ab3a5ae3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Mon, 25 Sep 2023 10:51:03 +0100 Subject: [PATCH 01/45] [Profiling] Fix set up process (#167067) So clients reported that they got stuck in the set up screen In the Universal Profling UI. And when the set up button was clicked an error happened: ``` An integration policy with the name elastic-universal-profiling-collector already exists. Please rename it or choose a different name. ``` This happens because when we were checking if the Collector and Symbolizer integrations were installed we weren't taking into consideration that the Fleet API is paginated. So if neither integration was available on the first page we just assumed the Profiling wasn't set up. This PR fixes it by adding a kuery filter in the Fleet API call to only look for out integrations. So we don't need to worry about paginating. --- .../profiling_data_access/common/fleet_policies.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/profiling_data_access/common/fleet_policies.ts b/x-pack/plugins/profiling_data_access/common/fleet_policies.ts index c3c489563b8ac..d3a9b51dd55d5 100644 --- a/x-pack/plugins/profiling_data_access/common/fleet_policies.ts +++ b/x-pack/plugins/profiling_data_access/common/fleet_policies.ts @@ -7,6 +7,7 @@ import { SavedObjectsClientContract } from '@kbn/core/server'; import type { PackagePolicyClient } from '@kbn/fleet-plugin/server'; +import { PACKAGE_POLICY_SAVED_OBJECT_TYPE, PackagePolicy } from '@kbn/fleet-plugin/common'; import { getApmPolicy } from './get_apm_policy'; import { PartialSetupState, ProfilingSetupOptions } from './setup'; @@ -21,9 +22,11 @@ async function getPackagePolicy({ packagePolicyClient: PackagePolicyClient; soClient: SavedObjectsClientContract; packageName: string; -}) { - const packagePolicies = await packagePolicyClient.list(soClient, {}); - return packagePolicies.items.find((pkg) => pkg.name === packageName); +}): Promise { + const packagePolicies = await packagePolicyClient.list(soClient, { + kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.name:${packageName}`, + }); + return packagePolicies.items[0]; } export async function getCollectorPolicy({ From e44362feae21d8a3e7d8090cabc7fed682d6956d Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 25 Sep 2023 06:24:07 -0400 Subject: [PATCH 02/45] skip failing test suite (#151854) --- .../test/security_solution_endpoint_api_int/apis/metadata.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts b/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts index b92a26e785127..c4778f7039a91 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts @@ -43,7 +43,8 @@ export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const endpointTestResources = getService('endpointTestResources'); - describe('test metadata apis', () => { + // Failing: See https://github.com/elastic/kibana/issues/151854 + describe.skip('test metadata apis', () => { describe('list endpoints GET route', () => { const numberOfHostsInFixture = 2; let agent1Timestamp: number; From 62e087a8a8c7507cd0ead1e54d2db36654c58e60 Mon Sep 17 00:00:00 2001 From: natasha-moore-elastic <137783811+natasha-moore-elastic@users.noreply.github.com> Date: Mon, 25 Sep 2023 11:38:41 +0100 Subject: [PATCH 03/45] [DOCS] Makes shards optional in Create pack API (#166639) ## Summary * Resolves https://github.com/elastic/security-docs/issues/3822. * Updates the `shards` object in Create pack API to optional for 8.10.1 and 8.11.0 onwards, per https://github.com/elastic/kibana/pull/166178 * Related to changes made in https://github.com/elastic/kibana/pull/166363. --- docs/api/osquery-manager/packs/create.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/osquery-manager/packs/create.asciidoc b/docs/api/osquery-manager/packs/create.asciidoc index 2fcfc58d43dba..280f6a1d9fe75 100644 --- a/docs/api/osquery-manager/packs/create.asciidoc +++ b/docs/api/osquery-manager/packs/create.asciidoc @@ -33,7 +33,7 @@ experimental[] Create packs. `policy_ids`:: (Optional, array) A list of agents policy IDs. -`shards`:: (Required, object) An object with shard configuration for policies included in the pack. For each policy, set the shard configuration to a percentage (1โ€“100) of target hosts. +`shards`:: (Optional, object) An object with shard configuration for policies included in the pack. For each policy, set the shard configuration to a percentage (1โ€“100) of target hosts. `queries`:: (Required, object) An object of queries. From d8b80901d7ea1b2f3ca333c9452f4962de720f3d Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 25 Sep 2023 12:50:57 +0200 Subject: [PATCH 04/45] [Uptime] Fixes monitor details overview (#166736) --- .../components/monitor/monitor_title.test.tsx | 33 +------- .../components/monitor/monitor_title.tsx | 83 ------------------- .../monitor_status.bar.test.tsx.snap | 75 ++++++++++++----- .../ssl_certificate.test.tsx.snap | 42 ++-------- .../status_bar/ssl_certificate.tsx | 13 ++- .../status_details/status_bar/status_bar.tsx | 68 ++++++++------- .../monitor/status_details/status_details.tsx | 25 +----- .../columns/define_connectors.test.tsx | 12 +-- .../columns/define_connectors.tsx | 44 ++-------- .../monitor_list/columns/enable_alert.tsx | 8 +- .../uptime/public/legacy_uptime/routes.tsx | 3 +- 11 files changed, 122 insertions(+), 284 deletions(-) diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/monitor_title.test.tsx b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/monitor_title.test.tsx index 3c98245760fcb..45b3c182084f6 100644 --- a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/monitor_title.test.tsx +++ b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/monitor_title.test.tsx @@ -13,7 +13,7 @@ import { render } from '../../lib/helper/rtl_helpers'; import * as reactRouterDom from 'react-router-dom'; import { Ping } from '../../../../common/runtime_types'; -import { MonitorPageTitle, MonitorPageTitleContent } from './monitor_title'; +import { MonitorPageTitle } from './monitor_title'; jest.mock('react-router-dom', () => { const originalModule = jest.requireActual('react-router-dom'); @@ -51,23 +51,6 @@ describe('MonitorTitle component', () => { }, }; - const defaultBrowserMonitorStatus: Ping = { - docId: 'few213kl', - timestamp: moment(new Date()).subtract(15, 'm').toString(), - monitor: { - duration: { - us: 1234567, - }, - id: 'browser', - status: 'up', - type: 'browser', - check_group: 'test-group', - }, - url: { - full: 'https://www.elastic.co/', - }, - }; - const monitorStatusWithName: Ping = { ...defaultMonitorStatus, monitor: { @@ -84,14 +67,12 @@ describe('MonitorTitle component', () => { render( <> - , { state: { monitorStatus: { status: monitorStatusWithName, loading: false } }, } ); expect(screen.getByText(monitorName)); - expect(screen.getByRole('switch')).toBeInTheDocument(); }); it('renders the user provided monitorId when the name is not present', () => { @@ -114,16 +95,4 @@ describe('MonitorTitle component', () => { ); expect(screen.getByText(defaultMonitorStatus!.url!.full!)); }); - - it('renders beta disclaimer for synthetics monitors', () => { - render(, { - state: { monitorStatus: { status: defaultBrowserMonitorStatus, loading: false } }, - }); - const betaLink = screen.getByRole('link', { - name: 'See more External link (opens in a new tab or window)', - }) as HTMLAnchorElement; - expect(betaLink).toBeInTheDocument(); - expect(betaLink.href).toBe('https://www.elastic.co/what-is/synthetic-monitoring'); - expect(screen.getByText('Browser (BETA)')).toBeInTheDocument(); - }); }); diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/monitor_title.tsx b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/monitor_title.tsx index a15b941e4e935..2a84d3acbf4ad 100644 --- a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/monitor_title.tsx +++ b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/monitor_title.tsx @@ -5,13 +5,10 @@ * 2.0. */ -import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiLink, EuiText } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; import React from 'react'; import { useSelector } from 'react-redux'; import { useMonitorId } from '../../hooks'; import { monitorStatusSelector } from '../../state/selectors'; -import { EnableMonitorAlert } from '../overview/monitor_list/columns/enable_alert'; import { Ping } from '../../../../common/runtime_types/ping'; import { useBreadcrumbs } from '../../hooks/use_breadcrumbs'; @@ -32,86 +29,6 @@ const getPageTitle = (monitorId: string, selectedMonitor: Ping | null) => { return monitorId; }; -export const MonitorPageTitleContent: React.FC = () => { - const monitorId = useMonitorId(); - const selectedMonitor = useSelector(monitorStatusSelector); - const type = selectedMonitor?.monitor?.type; - const isBrowser = type === 'browser'; - const renderMonitorType = (monitorType: string) => { - switch (monitorType) { - case 'http': - return ( - - ); - case 'tcp': - return ( - - ); - case 'icmp': - return ( - - ); - case 'browser': - return ( - - ); - default: - return ''; - } - }; - return ( - <> - - - - - - - - - {isBrowser && type && ( - - {renderMonitorType(type)}{' '} - - - )} - - {isBrowser && ( - - - - - - - - )} - - - ); -}; - export const MonitorPageTitle: React.FC = () => { const monitorId = useMonitorId(); diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/__snapshots__/monitor_status.bar.test.tsx.snap b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/__snapshots__/monitor_status.bar.test.tsx.snap index 5ebde1d72dd0d..77345c95164a6 100644 --- a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/__snapshots__/monitor_status.bar.test.tsx.snap +++ b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/__snapshots__/monitor_status.bar.test.tsx.snap @@ -12,58 +12,49 @@ Array [
, - .c0.c0.c0 { - width: 30%; - max-width: 250px; -} - -.c1.c1.c1 { - width: 70%; - overflow-wrap: anywhere; -} - -
Overall availability
0.00 %
Url
--
Monitor ID
Tags
+
+ Enable status alerts +
+
+
+
+
+
+ +
+
+
+
+
, ] `; diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/__snapshots__/ssl_certificate.test.tsx.snap b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/__snapshots__/ssl_certificate.test.tsx.snap index d80ca3bb00376..1e50379a09553 100644 --- a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/__snapshots__/ssl_certificate.test.tsx.snap +++ b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/__snapshots__/ssl_certificate.test.tsx.snap @@ -2,32 +2,19 @@ exports[`SSL Certificate component renders 1`] = ` Array [ - .c0.c0.c0 { - width: 30%; - max-width: 250px; -} - -
TLS Certificate
, -
, .c0.c0.c0 { - width: 70%; - overflow-wrap: anywhere; -} - -.c1.c1.c1 { margin: 0 0 0 4px; display: inline-block; color: inherit; }

Expires in 2 months

@@ -57,26 +44,13 @@ Array [ exports[`SSL Certificate component renders null if invalid date 1`] = ` Array [ - .c0.c0.c0 { - width: 30%; - max-width: 250px; -} - -
TLS Certificate
, -
, - .c0.c0.c0 { - width: 70%; - overflow-wrap: anywhere; -} - -
{ return ( <> - + - - - - + + - + ); }; diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/status_bar/status_bar.tsx b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/status_bar/status_bar.tsx index 50e4ca36dabc5..f122415d725c0 100644 --- a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/status_bar/status_bar.tsx +++ b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/status_bar/status_bar.tsx @@ -6,7 +6,6 @@ */ import React from 'react'; -import styled from 'styled-components'; import { EuiLink, EuiSpacer, @@ -16,6 +15,10 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; +import { useSelector } from 'react-redux'; +import { ENABLE_STATUS_ALERT } from '../../../overview/monitor_list/columns/translations'; +import { monitorStatusSelector } from '../../../../state/selectors'; +import { EnableMonitorAlert } from '../../../overview/monitor_list/columns/enable_alert'; import { MonitorSSLCertificate } from './ssl_certificate'; import * as labels from '../translations'; import { StatusByLocations } from './status_by_location'; @@ -31,20 +34,6 @@ import { formatAvailabilityValue } from '../availability_reporting/availability_ import { MonitorRedirects } from './monitor_redirects'; import { MonitorTags } from '../../../common/monitor_tags'; -export const MonListTitle = styled(EuiDescriptionListTitle)` - &&& { - width: 30%; - max-width: 250px; - } -`; - -export const MonListDescription = styled(EuiDescriptionListDescription)` - &&& { - width: 70%; - overflow-wrap: anywhere; - } -`; - export const renderMonitorType = (type: string | undefined) => { switch (type) { case 'http': @@ -77,24 +66,29 @@ export const MonitorStatusBar: React.FC = () => { const availability = (ups === 0 && downs === 0) || !ups ? 0 : (ups / (ups + downs)) * 100; + const selectedMonitor = useSelector(monitorStatusSelector); + return ( <>
- - {OverallAvailability} - + + {OverallAvailability} + - - {URL_LABEL} - + + {URL_LABEL} + {full ? ( { ) : ( '--' )} - - {MonitorIDLabel} - {monitorId} + + {MonitorIDLabel} + + {monitorId} + {monitorStatus?.monitor?.type && ( <> - {labels.typeLabel} - + + {labels.typeLabel} + + {renderMonitorType(monitorStatus?.monitor?.type)} - + )} - {TAGS_LABEL} - + {TAGS_LABEL} + - + {monitorStatus?.monitor?.project?.id && ( <> - {PROJECT_LABEL} - {monitorStatus?.monitor?.project.id} + {PROJECT_LABEL} + + {monitorStatus?.monitor?.project.id} + )} + {ENABLE_STATUS_ALERT} + {selectedMonitor && ( + + )} ); diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/status_details.tsx b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/status_details.tsx index 0c9c347fc8c80..48196a75f37b5 100644 --- a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/status_details.tsx +++ b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/status_details.tsx @@ -5,11 +5,10 @@ * 2.0. */ -import React, { useContext, useEffect, useState } from 'react'; +import React from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; import styled from 'styled-components'; import { LocationAvailability } from './location_availability/location_availability'; -import { UptimeRefreshContext } from '../../../contexts'; import { MonitorLocations } from '../../../../../common/runtime_types'; import { MonitorStatusBar } from './status_bar'; @@ -26,28 +25,6 @@ const WrapFlexItem = styled(EuiFlexItem)` `; export const MonitorStatusDetailsComponent = ({ monitorLocations }: MonitorStatusDetailsProps) => { - const { refreshApp } = useContext(UptimeRefreshContext); - - const [isTabActive] = useState(document.visibilityState); - const onTabActive = () => { - if (document.visibilityState === 'visible' && isTabActive === 'hidden') { - refreshApp(); - } - }; - - // Refreshing application state after Tab becomes active to render latest map state - // If application renders in when tab is not in focus it gives some unexpected behaviors - // Where map is not visible on change - useEffect(() => { - document.addEventListener('visibilitychange', onTabActive); - return () => { - document.removeEventListener('visibilitychange', onTabActive); - }; - - // we want this effect to execute exactly once after the component mounts - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - return ( diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/define_connectors.test.tsx b/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/define_connectors.test.tsx index aa257177970a1..29f0dd189594c 100644 --- a/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/define_connectors.test.tsx +++ b/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/define_connectors.test.tsx @@ -21,21 +21,23 @@ describe('EnableAlertComponent', () => { fireEvent.click(screen.getByTestId('uptimeDisplayDefineConnector')); - expect(screen.queryByTestId('uptimeSettingsDefineConnector')).not.toBeInTheDocument(); + expect(screen.queryByTestId('uptimeSettingsDefineConnector')).toBeInTheDocument(); }); it('shows label when showLabel is true', () => { - render(); - expect(screen.getByText(ENABLE_STATUS_ALERT)).toBeInTheDocument(); + render(); + expect(screen.getByLabelText(ENABLE_STATUS_ALERT)).toBeInTheDocument(); }); it('shows helpText when showHelpText is true', () => { - render(); + render(); + fireEvent.click(screen.getByTestId('uptimeDisplayDefineConnector')); + expect(screen.getByText(/Define a default connector/)).toBeInTheDocument(); }); it('renders popover on click when showPopover is true', () => { - render(); + render(); fireEvent.click(screen.getByTestId('uptimeDisplayDefineConnector')); diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/define_connectors.tsx b/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/define_connectors.tsx index 0a6040249a663..4ee8cb1c67d89 100644 --- a/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/define_connectors.tsx +++ b/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/define_connectors.tsx @@ -12,17 +12,7 @@ import { ReactRouterEuiLink } from '../../../common/react_router_helpers'; import { SETTINGS_ROUTE } from '../../../../../../common/constants'; import { ENABLE_STATUS_ALERT } from './translations'; -interface Props { - showPopover?: boolean; - showHelpText?: boolean; - showLabel?: boolean; -} - -export const DefineAlertConnectors = ({ - showPopover = false, - showHelpText = false, - showLabel = false, -}: Props) => { +export const DefineAlertConnectors = () => { const [isPopoverOpen, setIsPopoverOpen] = useState(false); const onButtonClick = () => setIsPopoverOpen((val) => !val); @@ -32,46 +22,22 @@ export const DefineAlertConnectors = ({ - - - - ), - }} - /> - ) : undefined - } - > + {}} + onChange={onButtonClick} checked={false} compressed={true} - disabled={!showPopover} data-test-subj={'uptimeDisplayDefineConnector'} /> } - isOpen={showPopover ? isPopoverOpen : false} + isOpen={isPopoverOpen} closePopover={closePopover} > diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/enable_alert.tsx b/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/enable_alert.tsx index b52aacd5abb6e..e7ff83f5ebae1 100644 --- a/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/enable_alert.tsx +++ b/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/enable_alert.tsx @@ -111,7 +111,7 @@ export const EnableMonitorAlert = ({ monitorId, selectedMonitor }: Props) => { compressed={!isMonitorPage} disabled={showSpinner} label={btnLabel} - showLabel={!!isMonitorPage} + showLabel={false} aria-label={btnLabel} onChange={onAlertClick} checked={!!hasAlert} @@ -126,10 +126,6 @@ export const EnableMonitorAlert = ({ monitorId, selectedMonitor }: Props) => {
) : ( - + ); }; diff --git a/x-pack/plugins/uptime/public/legacy_uptime/routes.tsx b/x-pack/plugins/uptime/public/legacy_uptime/routes.tsx index 43194e10735d6..269624a0c6dc0 100644 --- a/x-pack/plugins/uptime/public/legacy_uptime/routes.tsx +++ b/x-pack/plugins/uptime/public/legacy_uptime/routes.tsx @@ -30,7 +30,7 @@ import { SyntheticsCheckStepsPageHeader, SyntheticsCheckStepsPageRightSideItem, } from './pages/synthetics/synthetics_checks'; -import { MonitorPageTitle, MonitorPageTitleContent } from './components/monitor/monitor_title'; +import { MonitorPageTitle } from './components/monitor/monitor_title'; import { UptimeDatePicker } from './components/common/uptime_date_picker'; import { CertRefreshBtn } from './components/certificates/cert_refresh_btn'; import { CertificateTitle } from './components/certificates/certificate_title'; @@ -69,7 +69,6 @@ const getRoutes = (): RouteProps[] => { component: MonitorPage, dataTestSubj: 'uptimeMonitorPage', pageHeader: { - children: , pageTitle: , rightSideItems: [], }, From e4a088c7eb09fdb603ec165b77759d919c048cab Mon Sep 17 00:00:00 2001 From: Gerard Soldevila Date: Mon, 25 Sep 2023 13:24:42 +0200 Subject: [PATCH 05/45] [Migrations] Ensure individual migrator failures do not break consistency (#166924) ## Summary Tackles https://github.com/elastic/kibana/issues/158818 The goal of the PR is to introduce failures in single migrators at some of the crucial steps of the migration, testing that consistency is maintained, and that subsequent migration attempts can successfully complete the upgrade. This is done by _proxying_ the `Client` class, which uses the elasticsearch-js library underneath to perform all calls to ES. Inspired on https://github.com/elastic/kibana/pull/158995. --- .../elasticsearch_client_wrapper.ts | 81 +++++++ .../group5/dot_kibana_split.test.ts | 205 ++++++++++++++++++ .../migrations/kibana_migrator_test_kit.ts | 6 +- 3 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 src/core/server/integration_tests/saved_objects/migrations/elasticsearch_client_wrapper.ts diff --git a/src/core/server/integration_tests/saved_objects/migrations/elasticsearch_client_wrapper.ts b/src/core/server/integration_tests/saved_objects/migrations/elasticsearch_client_wrapper.ts new file mode 100644 index 0000000000000..66975bbba4409 --- /dev/null +++ b/src/core/server/integration_tests/saved_objects/migrations/elasticsearch_client_wrapper.ts @@ -0,0 +1,81 @@ +/* + * Copyright 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 { Client } from '@elastic/elasticsearch'; + +export type ElasticsearchClientWrapperFactory = (client: Client) => Client; + +interface GetElasticsearchClientWrapperFactoryParams { + failOn: (methodName: string, methodArguments: any[]) => boolean; + errorDelaySeconds?: number; +} + +export const getElasticsearchClientWrapperFactory = ({ + failOn, + errorDelaySeconds, +}: GetElasticsearchClientWrapperFactoryParams): ElasticsearchClientWrapperFactory => { + const interceptClientMethod = (methodName: string, method: any): any => { + return new Proxy(method, { + apply: (applyTarget, thisArg, methodArguments) => { + if (failOn(methodName, methodArguments)) { + return new Promise((_, reject) => + setTimeout( + () => reject(`Error: esClient.${methodName}() failed unexpectedly`), + (errorDelaySeconds || 0) * 1000 + ) + ); + } + return Reflect.apply(applyTarget, thisArg, methodArguments); + }, + }); + }; + + const interceptClientApi = (apiName: string, api: any): any => + new Proxy(api, { + get(target, prop) { + return typeof target[prop] === 'function' + ? interceptClientMethod(`${apiName}.${prop.toString()}`, target[prop]) + : target[prop]; + }, + }); + + const wrapClient = (client: Client): any => + new Proxy(client, { + get(target, prop, receiver) { + switch (prop) { + // intercept top level esClient methods + case 'bulk': + case 'deleteByQuery': + case 'info': + case 'search': + case 'updateByQuery': + const clientMethod = Reflect.get(target, prop, receiver); + return interceptClientMethod(prop, clientMethod); + // intercept esClient APIs + case 'cluster': + case 'indices': + case 'tasks': + const clientApi = Reflect.get(target, prop, receiver); + return interceptClientApi(prop, clientApi); + // proxy child Clients too + case 'child': + return new Proxy(target[prop], { + apply(applyTarget, thisArg, argArray) { + const childClient = Reflect.apply(applyTarget, thisArg, argArray); + return wrapClient(childClient); + }, + }); + // do NOT intercept the rest of properties and symbols + default: + return Reflect.get(target, prop, receiver); + } + }, + }); + + return wrapClient; +}; diff --git a/src/core/server/integration_tests/saved_objects/migrations/group5/dot_kibana_split.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group5/dot_kibana_split.test.ts index 636e70cd9dd9e..25dc5a46a6793 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group5/dot_kibana_split.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group5/dot_kibana_split.test.ts @@ -29,6 +29,7 @@ import { } from '../kibana_migrator_test_kit'; import { delay, parseLogFile } from '../test_utils'; import '../jest_matchers'; +import { getElasticsearchClientWrapperFactory } from '../elasticsearch_client_wrapper'; // define a type => index distribution const RELOCATE_TYPES: Record = { @@ -58,6 +59,210 @@ describe('split .kibana index into multiple system indices', () => { await clearLog(logFilePathSecondRun); }); + describe('failure cases', () => { + const getFailingKibanaMigratorTestKit = async ({ + logFilePath, + failOn, + delaySeconds, + }: { + logFilePath: string; + failOn: (methodName: string, methodArgs: any[]) => boolean; + delaySeconds?: number; + }) => { + const clientWrapperFactory = getElasticsearchClientWrapperFactory({ + failOn, + errorDelaySeconds: delaySeconds, + }); + + return await getKibanaMigratorTestKit({ + types: typeRegistry.getAllTypes(), + kibanaIndex: MAIN_SAVED_OBJECT_INDEX, + defaultIndexTypesMap: DEFAULT_INDEX_TYPES_MAP, + logFilePath, + clientWrapperFactory, + }); + }; + + beforeEach(async () => { + esServer = await startElasticsearch({ + dataArchive: Path.join(__dirname, '..', 'archives', '7.7.2_xpack_100k_obj.zip'), + }); + }); + + describe('when the .kibana_task_manager migrator fails on the TRANSFORMED_DOCUMENTS_BULK_INDEX state, after the other ones have finished', () => { + it('is capable of completing the .kibana_task_manager migration in subsequent restart', async () => { + const { runMigrations: firstRun } = await getFailingKibanaMigratorTestKit({ + logFilePath: logFilePathFirstRun, + failOn: (methodName, methodArgs) => { + // fail on esClient.bulk({ index: '.kibana_task_manager_1' }) which supposedly causes + // the .kibana_task_manager migrator to fail on the TRANSFORMED_DOCUMENTS_BULK_INDEX state + return methodName === 'bulk' && methodArgs[0].index === '.kibana_task_manager_1'; + }, + delaySeconds: 90, // give the other migrators enough time to finish before failing + }); + + try { + await firstRun(); + throw new Error('First run should have thrown an error but it did not'); + } catch (error) { + expect(error.message).toEqual( + 'Unable to complete saved object migrations for the [.kibana_task_manager] index. Error: esClient.bulk() failed unexpectedly' + ); + } + }); + }); + + describe('when the .kibana migrator fails on the REINDEX_SOURCE_TO_TEMP_INDEX_BULK state', () => { + it('is capable of successfully performing the split migration in subsequent restart', async () => { + const { runMigrations: firstRun } = await getFailingKibanaMigratorTestKit({ + logFilePath: logFilePathFirstRun, + failOn: (methodName, methodArgs) => { + // fail on esClient.bulk({ index: '.kibana_8.11.0_reindex_temp_alias' }) which supposedly causes + // the .kibana migrator to fail on the REINDEX_SOURCE_TO_TEMP_INDEX_BULK + return ( + methodName === 'bulk' && + methodArgs[0].index === `.kibana_${currentVersion}_reindex_temp_alias` + ); + }, + delaySeconds: 10, // give the .kibana_task_manager migrator enough time to finish before failing + }); + + try { + await firstRun(); + throw new Error('First run should have thrown an error but it did not'); + } catch (error) { + expect(error.message).toEqual( + 'Unable to complete saved object migrations for the [.kibana] index. Error: esClient.bulk() failed unexpectedly' + ); + } + }); + }); + + describe('when the .kibana migrator fails on the CLONE_TEMP_TO_TARGET state', () => { + it('is capable of successfully performing the split migration in subsequent restart', async () => { + const { runMigrations: firstRun } = await getFailingKibanaMigratorTestKit({ + logFilePath: logFilePathFirstRun, + failOn: (methodName, methodArgs) => { + // fail on esClient.indices.clone({ index: '.kibana_8.11.0_reindex_temp', target: ... }) which supposedly causes + // the .kibana migrator to fail on the CLONE_TEMP_TO_TARGET + return ( + methodName === 'indices.clone' && + methodArgs[0].index === `.kibana_${currentVersion}_reindex_temp` && + methodArgs[0].target === `.kibana_${currentVersion}_001` + ); + }, + delaySeconds: 15, // give the other migrators enough time to finish before failing + }); + + try { + await firstRun(); + throw new Error('First run should have thrown an error but it did not'); + } catch (error) { + expect(error.message).toEqual( + 'Unable to complete saved object migrations for the [.kibana] index. Error: esClient.indices.clone() failed unexpectedly' + ); + } + }); + }); + + describe('when the .kibana migrator fails on the UPDATE_TARGET_MAPPINGS_PROPERTIES state', () => { + it('is capable of successfully performing the split migration in subsequent restart', async () => { + const { runMigrations: firstRun } = await getFailingKibanaMigratorTestKit({ + logFilePath: logFilePathFirstRun, + failOn: (methodName, methodArgs) => { + // fail on esClient.updateByQuery({ index: '.kibana_8.11.0_001' }) which supposedly causes + // the .kibana migrator to fail on the UPDATE_TARGET_MAPPINGS_PROPERTIES (pickup mappings' changes) + return ( + methodName === 'updateByQuery' && + methodArgs[0].index === `.kibana_${currentVersion}_001` + ); + }, + delaySeconds: 10, // give the other migrators enough time to finish before failing + }); + + try { + await firstRun(); + throw new Error('First run should have thrown an error but it did not'); + } catch (error) { + expect(error.message).toEqual( + 'Unable to complete saved object migrations for the [.kibana] index. Error: esClient.updateByQuery() failed unexpectedly' + ); + } + }); + }); + + describe('when the .kibana_analytics migrator fails on the CLONE_TEMP_TO_TARGET state', () => { + it('is capable of successfully performing the split migration in subsequent restart', async () => { + const { runMigrations: firstRun } = await getFailingKibanaMigratorTestKit({ + logFilePath: logFilePathFirstRun, + failOn: (methodName, methodArgs) => { + // fail on esClient.indices.clone({ index: '.kibana_8.11.0_reindex_temp', target: ... }) which supposedly causes + // the .kibana migrator to fail on the CLONE_TEMP_TO_TARGET + return ( + methodName === 'indices.clone' && + methodArgs[0].index === `.kibana_analytics_${currentVersion}_reindex_temp` && + methodArgs[0].target === `.kibana_analytics_${currentVersion}_001` + ); + }, + delaySeconds: 15, // give the other migrators enough time to finish before failing + }); + + try { + await firstRun(); + throw new Error('First run should have thrown an error but it did not'); + } catch (error) { + expect(error.message).toEqual( + 'Unable to complete saved object migrations for the [.kibana_analytics] index. Error: esClient.indices.clone() failed unexpectedly' + ); + } + }); + }); + + describe('when the .kibana_analytics migrator fails on the UPDATE_TARGET_MAPPINGS_PROPERTIES state', () => { + it('is capable of successfully performing the split migration in subsequent restart', async () => { + const { runMigrations: firstRun } = await getFailingKibanaMigratorTestKit({ + logFilePath: logFilePathFirstRun, + failOn: (methodName, methodArgs) => { + // fail on esClient.updateByQuery({ index: '.kibana_8.11.0_001' }) which supposedly causes + // the .kibana migrator to fail on the UPDATE_TARGET_MAPPINGS_PROPERTIES (pickup mappings' changes) + return ( + methodName === 'updateByQuery' && + methodArgs[0].index === `.kibana_analytics_${currentVersion}_001` + ); + }, + delaySeconds: 10, // give the other migrators enough time to finish before failing + }); + + try { + await firstRun(); + throw new Error('First run should have thrown an error but it did not'); + } catch (error) { + expect(error.message).toEqual( + 'Unable to complete saved object migrations for the [.kibana_analytics] index. Error: esClient.updateByQuery() failed unexpectedly' + ); + } + }); + }); + + afterEach(async () => { + const { runMigrations: secondRun } = await getKibanaMigratorTestKit({ + types: typeRegistry.getAllTypes(), + logFilePath: logFilePathSecondRun, + kibanaIndex: MAIN_SAVED_OBJECT_INDEX, + defaultIndexTypesMap: DEFAULT_INDEX_TYPES_MAP, + }); + const results = await secondRun(); + expect( + results + .flat() + .every((result) => result.status === 'migrated' || result.status === 'patched') + ).toEqual(true); + + await esServer?.stop(); + await delay(2); + }); + }); + describe('when migrating from a legacy version', () => { let migratorTestKitFactory: (logFilePath: string) => Promise; diff --git a/src/core/server/integration_tests/saved_objects/migrations/kibana_migrator_test_kit.ts b/src/core/server/integration_tests/saved_objects/migrations/kibana_migrator_test_kit.ts index a911fcdbdead5..1f6e9a7a58c77 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/kibana_migrator_test_kit.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/kibana_migrator_test_kit.ts @@ -50,6 +50,7 @@ import type { DocLinksServiceStart } from '@kbn/core-doc-links-server'; import type { NodeRoles } from '@kbn/core-node-server'; import { baselineDocuments, baselineTypes } from './kibana_migrator_test_kit.fixtures'; import { delay } from './test_utils'; +import type { ElasticsearchClientWrapperFactory } from './elasticsearch_client_wrapper'; export const defaultLogFilePath = Path.join(__dirname, 'kibana_migrator_test_kit.log'); @@ -76,6 +77,7 @@ export interface KibanaMigratorTestKitParams { types?: Array>; defaultIndexTypesMap?: IndexTypesMap; logFilePath?: string; + clientWrapperFactory?: ElasticsearchClientWrapperFactory; } export interface KibanaMigratorTestKit { @@ -134,6 +136,7 @@ export const getKibanaMigratorTestKit = async ({ types = [], logFilePath = defaultLogFilePath, nodeRoles = defaultNodeRoles, + clientWrapperFactory, }: KibanaMigratorTestKitParams = {}): Promise => { let hasRun = false; const loggingSystem = new LoggingSystem(); @@ -145,7 +148,8 @@ export const getKibanaMigratorTestKit = async ({ const loggingConf = await firstValueFrom(configService.atPath('logging')); loggingSystem.upgrade(loggingConf); - const client = await getElasticsearchClient(configService, loggerFactory, kibanaVersion); + const rawClient = await getElasticsearchClient(configService, loggerFactory, kibanaVersion); + const client = clientWrapperFactory ? clientWrapperFactory(rawClient) : rawClient; const typeRegistry = new SavedObjectTypeRegistry(); From 258e9848d16ccc0a6d184983cbf531c2e1b033d5 Mon Sep 17 00:00:00 2001 From: Maryam Saeidi Date: Mon, 25 Sep 2023 15:49:12 +0200 Subject: [PATCH 06/45] Fix Errors rules link on observability alert page (#167027) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #167004 ## Summary This PR fixes the Errors stat link and improves the code using the Rules locator. ![image](https://github.com/elastic/kibana/assets/12370520/bb836360-3ee9-4b12-b079-7fa9ad26bbf7) ## ๐Ÿงช How to test - Please check all the statuses (Disabled, Snoozed, Errors) to make sure links work as expected. --- .../public/pages/alerts/alerts.tsx | 12 ++++- .../alerts/components/rule_stats.test.tsx | 53 +++++++++++++------ .../pages/alerts/components/rule_stats.tsx | 31 +++++------ .../observability/public/plugin.mock.tsx | 9 ++-- 4 files changed, 70 insertions(+), 35 deletions(-) diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts.tsx index 27ae07cbf768d..08b89dad773ce 100644 --- a/x-pack/plugins/observability/public/pages/alerts/alerts.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/alerts.tsx @@ -15,6 +15,8 @@ import { AlertConsumers } from '@kbn/rule-data-utils'; import { useBreadcrumbs } from '@kbn/observability-shared-plugin/public'; import { MaintenanceWindowCallout } from '@kbn/alerts-ui-shared'; +import { rulesLocatorID } from '../../../common'; +import { RulesParams } from '../../locators/rules'; import { useKibana } from '../../utils/kibana_react'; import { useHasData } from '../../hooks/use_has_data'; import { usePluginContext } from '../../hooks/use_plugin_context'; @@ -53,6 +55,9 @@ function InternalAlertsPage() { }, http, notifications: { toasts }, + share: { + url: { locators }, + }, triggersActionsUi: { alertsTableConfigurationRegistry, getAlertsSearchBar: AlertsSearchBar, @@ -179,7 +184,12 @@ function InternalAlertsPage() { pageTitle: ( <>{i18n.translate('xpack.observability.alertsTitle', { defaultMessage: 'Alerts' })} ), - rightSideItems: renderRuleStats(ruleStats, manageRulesHref, ruleStatsLoading), + rightSideItems: renderRuleStats( + ruleStats, + manageRulesHref, + ruleStatsLoading, + locators.get(rulesLocatorID) + ), }} > diff --git a/x-pack/plugins/observability/public/pages/alerts/components/rule_stats.test.tsx b/x-pack/plugins/observability/public/pages/alerts/components/rule_stats.test.tsx index aaeab5d7855f7..758df7224be2d 100644 --- a/x-pack/plugins/observability/public/pages/alerts/components/rule_stats.test.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/components/rule_stats.test.tsx @@ -6,7 +6,9 @@ */ import { renderRuleStats } from './rule_stats'; -import { render, screen } from '@testing-library/react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { LocatorPublic } from '@kbn/share-plugin/common'; +import { RulesParams } from '../../../locators/rules'; const RULES_PAGE_LINK = '/app/observability/alerts/rules'; const STAT_CLASS = 'euiStat'; @@ -14,6 +16,14 @@ const STAT_TITLE_PRIMARY_SELECTOR = '[class*="euiStat__title-primary"]'; const STAT_BUTTON_CLASS = 'euiButtonEmpty'; describe('Rule stats', () => { + const mockedLocator = { + navigate: jest.fn(), + } as any as LocatorPublic; + + beforeEach(() => { + jest.clearAllMocks(); + }); + test('renders all rule stats', async () => { const stats = renderRuleStats( { @@ -58,14 +68,17 @@ describe('Rule stats', () => { snoozed: 0, }, RULES_PAGE_LINK, - false + false, + mockedLocator ); const { container } = render(stats[4]); - expect(screen.getByText('Disabled').closest('a')).toHaveAttribute( - 'href', - `${RULES_PAGE_LINK}?_a=(lastResponse:!(),status:!(disabled))` - ); + fireEvent.click(screen.getByText('Disabled')); + + expect(mockedLocator.navigate).toHaveBeenCalledWith( + { status: ['disabled'] }, + { replace: false } + ); expect(container.getElementsByClassName(STAT_BUTTON_CLASS).length).toBe(1); }); @@ -115,14 +128,18 @@ describe('Rule stats', () => { snoozed: 1, }, RULES_PAGE_LINK, - false + false, + mockedLocator ); const { container } = render(stats[3]); - expect(container.getElementsByClassName(STAT_BUTTON_CLASS).length).toBe(1); - expect(screen.getByText('Snoozed').closest('a')).toHaveAttribute( - 'href', - `${RULES_PAGE_LINK}?_a=(lastResponse:!(),status:!(snoozed))` + + fireEvent.click(screen.getByText('Snoozed')); + + expect(mockedLocator.navigate).toHaveBeenCalledWith( + { status: ['snoozed'] }, + { replace: false } ); + expect(container.getElementsByClassName(STAT_BUTTON_CLASS).length).toBe(1); }); test('snoozed stat count is link-colored, when there are snoozed rules', async () => { @@ -171,14 +188,18 @@ describe('Rule stats', () => { snoozed: 0, }, RULES_PAGE_LINK, - false + false, + mockedLocator ); const { container } = render(stats[2]); - expect(container.getElementsByClassName(STAT_BUTTON_CLASS).length).toBe(1); - expect(screen.getByText('Errors').closest('a')).toHaveAttribute( - 'href', - `${RULES_PAGE_LINK}?_a=(lastResponse:!(error),status:!())` + + fireEvent.click(screen.getByText('Errors')); + + expect(mockedLocator.navigate).toHaveBeenCalledWith( + { lastResponse: ['failed'] }, + { replace: false } ); + expect(container.getElementsByClassName(STAT_BUTTON_CLASS).length).toBe(1); }); test('errors stat count is link-colored, when there are error rules', () => { diff --git a/x-pack/plugins/observability/public/pages/alerts/components/rule_stats.tsx b/x-pack/plugins/observability/public/pages/alerts/components/rule_stats.tsx index f85a6a766b17c..005ba7ccaec82 100644 --- a/x-pack/plugins/observability/public/pages/alerts/components/rule_stats.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/components/rule_stats.tsx @@ -8,8 +8,10 @@ import React from 'react'; import { EuiButtonEmpty, EuiStat } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { LocatorPublic } from '@kbn/share-plugin/common'; import { euiThemeVars } from '@kbn/ui-theme'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; +import { RulesParams } from '../../../locators/rules'; export interface RuleStatsState { total: number; @@ -18,7 +20,7 @@ export interface RuleStatsState { error: number; snoozed: number; } -type StatType = 'disabled' | 'snoozed' | 'error'; +type Status = 'disabled' | 'snoozed' | 'error'; const Divider = euiStyled.div` border-right: 1px solid ${euiThemeVars.euiColorLightShade}; @@ -41,33 +43,32 @@ const ConditionalWrap = ({ children: JSX.Element; }): JSX.Element => (condition ? wrap(children) : children); -const getStatCount = (stats: RuleStatsState, statType: StatType) => { - if (statType === 'snoozed') return stats.snoozed + stats.muted; - return stats[statType]; +const getStatCount = (stats: RuleStatsState, status: Status) => { + if (status === 'snoozed') return stats.snoozed + stats.muted; + return stats[status]; }; export const renderRuleStats = ( ruleStats: RuleStatsState, manageRulesHref: string, - ruleStatsLoading: boolean + ruleStatsLoading: boolean, + rulesLocator?: LocatorPublic ) => { - const createRuleStatsLink = (stats: RuleStatsState, statType: StatType) => { - const count = getStatCount(stats, statType); - let statsLink = `${manageRulesHref}?_a=(lastResponse:!(),status:!())`; + const handleNavigateToRules = async (stats: RuleStatsState, status: Status) => { + const count = getStatCount(stats, status); if (count > 0) { - switch (statType) { + switch (status) { case 'error': - statsLink = `${manageRulesHref}?_a=(lastResponse:!(error),status:!())`; + await rulesLocator?.navigate({ lastResponse: ['failed'] }, { replace: false }); break; case 'snoozed': case 'disabled': - statsLink = `${manageRulesHref}?_a=(lastResponse:!(),status:!(${statType}))`; + await rulesLocator?.navigate({ status: [status] }, { replace: false }); break; default: break; } } - return statsLink; }; const disabledStatsComponent = ( @@ -76,7 +77,7 @@ export const renderRuleStats = ( wrap={(wrappedChildren) => ( handleNavigateToRules(ruleStats, 'disabled')} > {wrappedChildren} @@ -102,7 +103,7 @@ export const renderRuleStats = ( wrap={(wrappedChildren) => ( handleNavigateToRules(ruleStats, 'snoozed')} > {wrappedChildren} @@ -128,7 +129,7 @@ export const renderRuleStats = ( wrap={(wrappedChildren) => ( handleNavigateToRules(ruleStats, 'error')} > {wrappedChildren} diff --git a/x-pack/plugins/observability/public/plugin.mock.tsx b/x-pack/plugins/observability/public/plugin.mock.tsx index be663d15e444d..9732f67aac35f 100644 --- a/x-pack/plugins/observability/public/plugin.mock.tsx +++ b/x-pack/plugins/observability/public/plugin.mock.tsx @@ -4,11 +4,13 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import React from 'react'; import { mockCasesContract } from '@kbn/cases-plugin/public/mocks'; import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks'; +import { sharePluginMock } from '@kbn/share-plugin/public/mocks'; import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks'; const triggersActionsUiStartMock = { @@ -97,12 +99,13 @@ export const observabilityPublicPluginsStartMock = { cases: mockCasesContract(), charts: chartPluginMock.createStartContract(), contentManagement: contentManagementMock.createStartContract(), - triggersActionsUi: triggersActionsUiStartMock.createStart(), data: dataPluginMock.createStartContract(), - dataViews: dataViews.createStart(), dataViewEditor: dataViewEditor.createStart(), - lens: null, + dataViews: dataViews.createStart(), discover: null, + lens: null, + share: sharePluginMock.createStartContract(), + triggersActionsUi: triggersActionsUiStartMock.createStart(), unifiedSearch: unifiedSearchPluginMock.createStartContract(), }; }, From ab2881feef74effce344dfa4480dd91d50d4c7b5 Mon Sep 17 00:00:00 2001 From: Alex Szabo Date: Mon, 25 Sep 2023 15:58:28 +0200 Subject: [PATCH 07/45] Further test failures (#167148) ## Summary --- src/dev/build/tasks/fleet/download_elastic_gpg_key.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dev/build/tasks/fleet/download_elastic_gpg_key.ts b/src/dev/build/tasks/fleet/download_elastic_gpg_key.ts index 483a342ba300e..6cd0b351c4d31 100644 --- a/src/dev/build/tasks/fleet/download_elastic_gpg_key.ts +++ b/src/dev/build/tasks/fleet/download_elastic_gpg_key.ts @@ -13,9 +13,9 @@ import { ToolingLog } from '@kbn/tooling-log'; import { downloadToDisk } from '../../lib'; const ARTIFACTS_URL = 'https://artifacts.elastic.co/'; -const GPG_KEY_NAME = 'GPG-KEY-elasticsearch'; +const GPG_KEY_NAME = 'GPG-KEY-elasticsearch.sha1'; const GPG_KEY_SHA512 = - '62a567354286deb02baf5fc6b82ddf6c7067898723463da9ae65b132b8c6d6f064b2874e390885682376228eed166c1c82fe7f11f6c9a69f0c157029c548fa3d'; + '84ee193cc337344d9a7da9021daf3f5ede83f5f1ab049d169f3634921529dcd096abf7a91eec7f26f3a6913e5e38f88f69a5e2ce79ad155d46edc75705a648c6'; export async function downloadElasticGpgKey(pkgDir: string, log: ToolingLog) { const gpgKeyUrl = ARTIFACTS_URL + GPG_KEY_NAME; From a71242686acd0a43f446af7ce606b36f161819fd Mon Sep 17 00:00:00 2001 From: Alexi Doak <109488926+doakalexi@users.noreply.github.com> Date: Mon, 25 Sep 2023 07:02:23 -0700 Subject: [PATCH 08/45] =?UTF-8?q?[ResponseOps]=20[Alerting]=20Removing=20s?= =?UTF-8?q?kip=20on=20x-pack/test/alerting=5Fapi=5Fintegration/security=5F?= =?UTF-8?q?and=5Fspaces/group2/tests/telemetry/alerting=5Fand=5Factions=5F?= =?UTF-8?q?telemetry=C2=B7ts=20(#166985)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves https://github.com/elastic/kibana/issues/140973 ## Summary Failure were caused by ``` Error: read ECONNRESET at TCP.onStreamRead (node:internal/stream_base_commons:217:20) { errno: -104, code: 'ECONNRESET', syscall: 'read', response: undefined } ``` Flaky test runner x 250 https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/3210 --- .../group2/tests/telemetry/alerting_and_actions_telemetry.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/telemetry/alerting_and_actions_telemetry.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/telemetry/alerting_and_actions_telemetry.ts index ddc90ec10e9b6..02a41b6de7afa 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/telemetry/alerting_and_actions_telemetry.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/telemetry/alerting_and_actions_telemetry.ts @@ -26,8 +26,7 @@ export default function createAlertingAndActionsTelemetryTests({ getService }: F const esTestIndexTool = new ESTestIndexTool(es, retry); const supertestWithoutAuth = getService('supertestWithoutAuth'); - // FLAKY: https://github.com/elastic/kibana/issues/140973 - describe.skip('telemetry', () => { + describe('telemetry', () => { const objectRemover = new ObjectRemover(supertest); const alwaysFiringRuleId: { [key: string]: string } = {}; From dfcf60ae33f9482465e5c549023a6ec7b7604acd Mon Sep 17 00:00:00 2001 From: Vadim Kibana <82822460+vadimkibana@users.noreply.github.com> Date: Mon, 25 Sep 2023 16:04:28 +0200 Subject: [PATCH 09/45] Remove deprecated EUI components in kibana_react (#166225) ## Summary Closes https://github.com/elastic/kibana/issues/161422 In this PR: - [x] Removes `KibanaPageTemplate` utilities from `kibana_react` - [x] Migrates remaining users of `KibanaPageTemplate` from `kibana_react` to the one from `@kbn/shared-ux-page-kibana-template` - [x] `src/plugins/home/public/application/components/tutorial_directory.js` - [x] `src/plugins/home/public/application/components/tutorial/tutorial.js` - [x] `x-pack/plugins/osquery/public/components/empty_state.tsx` ## Visual Changes Below are the main visual differences this PR introduces. Sample data page before: Screenshot 2023-09-13 at 12 12 11 Sample data page now: Screenshot 2023-09-13 at 12 12 18 Tutorials page before: Screenshot 2023-09-13 at 13 09 58 Tutorials page now: Screenshot 2023-09-13 at 13 10 04 --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../__snapshots__/page_template.test.tsx.snap | 2 +- .../page_template_inner.test.tsx.snap | 3 +- .../impl/src/page_template_inner.tsx | 3 +- .../__snapshots__/tutorial.test.js.snap | 276 +++++------ .../components/tutorial/tutorial.js | 10 +- .../components/tutorial_directory.js | 4 +- src/plugins/kibana_react/public/index.ts | 4 - .../__snapshots__/page_template.test.tsx.snap | 440 ------------------ .../public/page_template/index.ts | 4 - .../page_template/no_data_page/index.ts | 1 - .../no_data_config_page/index.tsx | 9 - .../no_data_config_page.tsx | 38 -- .../public/page_template/page_template.scss | 22 - .../page_template/page_template.test.tsx | 173 ------- .../public/page_template/page_template.tsx | 98 ---- .../page_template/page_template_inner.tsx | 61 --- .../public/page_template/util/constants.ts | 20 - .../public/page_template/util/index.ts | 1 - .../page_template/with_solution_nav.tsx | 77 --- .../osquery/public/components/empty_state.tsx | 2 +- x-pack/plugins/osquery/tsconfig.json | 1 + 21 files changed, 157 insertions(+), 1092 deletions(-) delete mode 100644 src/plugins/kibana_react/public/page_template/__snapshots__/page_template.test.tsx.snap delete mode 100644 src/plugins/kibana_react/public/page_template/no_data_page/no_data_config_page/index.tsx delete mode 100644 src/plugins/kibana_react/public/page_template/no_data_page/no_data_config_page/no_data_config_page.tsx delete mode 100644 src/plugins/kibana_react/public/page_template/page_template.scss delete mode 100644 src/plugins/kibana_react/public/page_template/page_template.test.tsx delete mode 100644 src/plugins/kibana_react/public/page_template/page_template.tsx delete mode 100644 src/plugins/kibana_react/public/page_template/page_template_inner.tsx delete mode 100644 src/plugins/kibana_react/public/page_template/util/constants.ts delete mode 100644 src/plugins/kibana_react/public/page_template/with_solution_nav.tsx diff --git a/packages/shared-ux/page/kibana_template/impl/src/__snapshots__/page_template.test.tsx.snap b/packages/shared-ux/page/kibana_template/impl/src/__snapshots__/page_template.test.tsx.snap index c57c90acbdcf7..09421e4cb5dd7 100644 --- a/packages/shared-ux/page/kibana_template/impl/src/__snapshots__/page_template.test.tsx.snap +++ b/packages/shared-ux/page/kibana_template/impl/src/__snapshots__/page_template.test.tsx.snap @@ -3,7 +3,7 @@ exports[`KibanaPageTemplate render basic template 1`] = `
<_EuiPageHeader diff --git a/packages/shared-ux/page/kibana_template/impl/src/page_template_inner.tsx b/packages/shared-ux/page/kibana_template/impl/src/page_template_inner.tsx index f9b9dcd247de6..5da29ba797041 100644 --- a/packages/shared-ux/page/kibana_template/impl/src/page_template_inner.tsx +++ b/packages/shared-ux/page/kibana_template/impl/src/page_template_inner.tsx @@ -68,7 +68,8 @@ export const KibanaPageTemplateInner: FC = ({ // the following props can be removed to allow the template to auto-handle // the fixed header and banner heights. offset={0} - minHeight={0} + minHeight={header ? 'calc(100vh - var(--euiFixedHeadersOffset, 0))' : 0} + grow={header ? false : undefined} {...rest} > {sideBar} diff --git a/src/plugins/home/public/application/components/tutorial/__snapshots__/tutorial.test.js.snap b/src/plugins/home/public/application/components/tutorial/__snapshots__/tutorial.test.js.snap index bd4e658b04a99..2cd4388680751 100644 --- a/src/plugins/home/public/application/components/tutorial/__snapshots__/tutorial.test.js.snap +++ b/src/plugins/home/public/application/components/tutorial/__snapshots__/tutorial.test.js.snap @@ -1,160 +1,166 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`isCloudEnabled is false should not render instruction toggle when ON_PREM_ELASTIC_CLOUD instructions are not provided 1`] = ` - -
- - - +
+ -
- + "prepend": [Function], + } + } + description="tutorial used to drive jest tests" + notices={null} + title="jest test tutorial" + /> + + +
+ + `; exports[`isCloudEnabled is false should render ON_PREM instructions with instruction toggle 1`] = ` - -
- +
+ - - - + + + + + + - - - -
- +
+ + `; exports[`should render ELASTIC_CLOUD instructions when isCloudEnabled is true 1`] = ` - -
- - - +
+ -
- + "prepend": [Function], + } + } + description="tutorial used to drive jest tests" + iconType="logoApache" + notices={null} + title="jest test tutorial" + /> + + +
+ + `; diff --git a/src/plugins/home/public/application/components/tutorial/tutorial.js b/src/plugins/home/public/application/components/tutorial/tutorial.js index de222dbe6155d..620da42169c35 100644 --- a/src/plugins/home/public/application/components/tutorial/tutorial.js +++ b/src/plugins/home/public/application/components/tutorial/tutorial.js @@ -18,7 +18,7 @@ import * as StatusCheckStates from './status_check_states'; import { injectI18n, FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { getServices } from '../../kibana_services'; -import { KibanaPageTemplate } from '@kbn/kibana-react-plugin/public'; +import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; const INSTRUCTIONS_TYPE = { ELASTIC_CLOUD: 'elasticCloud', @@ -360,7 +360,7 @@ class TutorialUi extends React.Component { render() { let content; if (this.state.notFound) { - content = ( + return ( {content}; + return ( + + {content} + + ); } } diff --git a/src/plugins/home/public/application/components/tutorial_directory.js b/src/plugins/home/public/application/components/tutorial_directory.js index cde8b86f5df22..c5a4c1b27fbab 100644 --- a/src/plugins/home/public/application/components/tutorial_directory.js +++ b/src/plugins/home/public/application/components/tutorial_directory.js @@ -16,7 +16,7 @@ import { SampleDataTab } from '@kbn/home-sample-data-tab'; import { i18n } from '@kbn/i18n'; import { Synopsis } from './synopsis'; import { getServices } from '../kibana_services'; -import { KibanaPageTemplate } from '@kbn/kibana-react-plugin/public'; +import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; import { getTutorials } from '../load_tutorials'; const SAMPLE_DATA_TAB_ID = 'sampleData'; @@ -257,7 +257,7 @@ class TutorialDirectoryUi extends React.Component { rightSideItems: headerLinks ? [headerLinks] : [], }} > - {this.renderTabContent()} + {this.renderTabContent()}
); } diff --git a/src/plugins/kibana_react/public/index.ts b/src/plugins/kibana_react/public/index.ts index f92739d045439..7954559206bb7 100644 --- a/src/plugins/kibana_react/public/index.ts +++ b/src/plugins/kibana_react/public/index.ts @@ -54,17 +54,13 @@ export { POSITIONS, WEIGHTS, TOOLBAR_BUTTON_SIZES, ToolbarButton } from './toolb export { reactRouterNavigate, reactRouterOnClickHandler } from './react_router_navigate'; export type { - KibanaPageTemplateProps, NoDataPageActions, NoDataPageActionsProps, NoDataPageProps, ElasticAgentCardProps, } from './page_template'; export { - KibanaPageTemplate, KibanaPageTemplateSolutionNavAvatar, - NO_DATA_PAGE_MAX_WIDTH, - NO_DATA_PAGE_TEMPLATE_PROPS, NO_DATA_RECOMMENDED, NoDataPage, ElasticAgentCard, diff --git a/src/plugins/kibana_react/public/page_template/__snapshots__/page_template.test.tsx.snap b/src/plugins/kibana_react/public/page_template/__snapshots__/page_template.test.tsx.snap deleted file mode 100644 index 4dea9549670f3..0000000000000 --- a/src/plugins/kibana_react/public/page_template/__snapshots__/page_template.test.tsx.snap +++ /dev/null @@ -1,440 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`KibanaPageTemplate render basic template 1`] = ` -
-
-
-
-
-
-
-

- test -

-
-
-
-
-
- test -
-
-
-
-
-
-
-
-
-
-
-`; - -exports[`KibanaPageTemplate render custom empty prompt only 1`] = ` - - - custom test - - } - /> - -`; - -exports[`KibanaPageTemplate render custom empty prompt with page header 1`] = ` - - - custom test - - } - /> - -`; - -exports[`KibanaPageTemplate render default empty prompt 1`] = ` - -`; - -exports[`KibanaPageTemplate render noDataContent 1`] = ` - -`; - -exports[`KibanaPageTemplate render solutionNav 1`] = ` -
-
- - -
-
-
-
-
-
-
-
-

- test -

-
-
-
-
-
- test -
-
-
-
-
-
-
-
-
-
-
-
-`; diff --git a/src/plugins/kibana_react/public/page_template/index.ts b/src/plugins/kibana_react/public/page_template/index.ts index fda644a284797..65a5db433593a 100644 --- a/src/plugins/kibana_react/public/page_template/index.ts +++ b/src/plugins/kibana_react/public/page_template/index.ts @@ -6,9 +6,5 @@ * Side Public License, v 1. */ -export type { KibanaPageTemplateProps } from './page_template'; -export { KibanaPageTemplate } from './page_template'; export { KibanaPageTemplateSolutionNavAvatar, KibanaPageTemplateSolutionNav } from './solution_nav'; export * from './no_data_page'; -export { withSolutionNav } from './with_solution_nav'; -export { NO_DATA_PAGE_MAX_WIDTH, NO_DATA_PAGE_TEMPLATE_PROPS } from './util'; diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/index.ts b/src/plugins/kibana_react/public/page_template/no_data_page/index.ts index b5a11722dd397..55661ad6f14f7 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/index.ts +++ b/src/plugins/kibana_react/public/page_template/no_data_page/index.ts @@ -8,4 +8,3 @@ export * from './no_data_page'; export * from './no_data_card'; -export * from './no_data_config_page'; diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_config_page/index.tsx b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_config_page/index.tsx deleted file mode 100644 index 0bdde40021398..0000000000000 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_config_page/index.tsx +++ /dev/null @@ -1,9 +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. - */ - -export { NoDataConfigPage, NoDataConfigPageWithSolutionNavBar } from './no_data_config_page'; diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_config_page/no_data_config_page.tsx b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_config_page/no_data_config_page.tsx deleted file mode 100644 index cae591f571c79..0000000000000 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_config_page/no_data_config_page.tsx +++ /dev/null @@ -1,38 +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 { EuiPageTemplate_Deprecated as EuiPageTemplate } from '@elastic/eui'; -import React from 'react'; -import { NoDataPage } from '../no_data_page'; -import { withSolutionNav } from '../../with_solution_nav'; -import { KibanaPageTemplateProps } from '../../page_template'; -import { getClasses, NO_DATA_PAGE_TEMPLATE_PROPS } from '../../util'; - -export const NoDataConfigPage = (props: KibanaPageTemplateProps) => { - const { className, noDataConfig, ...rest } = props; - - if (!noDataConfig) { - return null; - } - - const template = NO_DATA_PAGE_TEMPLATE_PROPS.template; - const classes = getClasses(template, className); - - return ( - - - - ); -}; - -export const NoDataConfigPageWithSolutionNavBar = withSolutionNav(NoDataConfigPage); diff --git a/src/plugins/kibana_react/public/page_template/page_template.scss b/src/plugins/kibana_react/public/page_template/page_template.scss deleted file mode 100644 index d94daec56235f..0000000000000 --- a/src/plugins/kibana_react/public/page_template/page_template.scss +++ /dev/null @@ -1,22 +0,0 @@ -.kbnPageTemplate__pageSideBar { - overflow: hidden; - // Temporary hack till the sizing is changed directly in EUI - min-width: 248px; - - @include euiCanAnimate { - transition: min-width $euiAnimSpeedFast $euiAnimSlightResistance; - } - - &.kbnPageTemplate__pageSideBar--shrink { - min-width: $euiSizeXXL; - } - - .kbnPageTemplate--centeredBody & { - border-bottom: $euiBorderThin; - - @include euiBreakpoint('m', 'l', 'xl') { - border-bottom: none; - border-right: $euiBorderThin; - } - } -} diff --git a/src/plugins/kibana_react/public/page_template/page_template.test.tsx b/src/plugins/kibana_react/public/page_template/page_template.test.tsx deleted file mode 100644 index aff6082902a34..0000000000000 --- a/src/plugins/kibana_react/public/page_template/page_template.test.tsx +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React from 'react'; -import { shallow, render } from 'enzyme'; -import { KibanaPageTemplate, KibanaPageTemplateProps } from './page_template'; -import { EuiEmptyPrompt } from '@elastic/eui'; -import { KibanaPageTemplateSolutionNavProps } from './solution_nav'; - -const navItems: KibanaPageTemplateSolutionNavProps['items'] = [ - { - name: 'Ingest', - id: '1', - items: [ - { - name: 'Ingest Node Pipelines', - id: '1.1', - }, - { - name: 'Logstash Pipelines', - id: '1.2', - }, - { - name: 'Beats Central Management', - id: '1.3', - }, - ], - }, - { - name: 'Data', - id: '2', - items: [ - { - name: 'Index Management', - id: '2.1', - }, - { - name: 'Index Lifecycle Policies', - id: '2.2', - }, - { - name: 'Snapshot and Restore', - id: '2.3', - }, - ], - }, -]; - -const noDataConfig: KibanaPageTemplateProps['noDataConfig'] = { - solution: 'Elastic', - actions: { - elasticAgent: {}, - beats: {}, - custom: {}, - }, - docsLink: 'test', -}; - -describe('KibanaPageTemplate', () => { - test('render default empty prompt', () => { - const component = shallow( - - ); - expect(component).toMatchSnapshot(); - }); - - test('render custom empty prompt only', () => { - const component = shallow( - - custom test} /> - - ); - expect(component).toMatchSnapshot(); - }); - - test('render custom empty prompt with page header', () => { - const component = shallow( - - custom test} /> - - ); - expect(component).toMatchSnapshot(); - }); - - test('render basic template', () => { - const component = render( - - ); - expect(component).toMatchSnapshot(); - }); - - test('render solutionNav', () => { - const component = render( - - ); - expect(component).toMatchSnapshot(); - expect(component.find('div.kbnPageTemplate__pageSideBar').length).toBe(1); - }); - - test('render noDataContent', () => { - const component = shallow( - - ); - expect(component).toMatchSnapshot(); - }); - - test('render sidebar classes', () => { - const component = shallow( - - ); - expect(component.html().includes('kbnPageTemplate__pageSideBar customClass')).toBe(true); - }); -}); diff --git a/src/plugins/kibana_react/public/page_template/page_template.tsx b/src/plugins/kibana_react/public/page_template/page_template.tsx deleted file mode 100644 index 42ba9d1873587..0000000000000 --- a/src/plugins/kibana_react/public/page_template/page_template.tsx +++ /dev/null @@ -1,98 +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 './page_template.scss'; - -import React, { FunctionComponent } from 'react'; -import { EuiPageTemplateProps_Deprecated } from '@elastic/eui'; -import { KibanaPageTemplateSolutionNavProps } from './solution_nav'; - -import { - NoDataPageProps, - NoDataConfigPage, - NoDataConfigPageWithSolutionNavBar, -} from './no_data_page'; -import { KibanaPageTemplateInner, KibanaPageTemplateWithSolutionNav } from './page_template_inner'; - -/** - * A thin wrapper around EuiPageTemplate with a few Kibana specific additions - * @deprecated Use `KibanaPageTemplateProps` from `@kbn/shared-ux-page-kibana-template-types`. - */ -export type KibanaPageTemplateProps = EuiPageTemplateProps_Deprecated & { - /** - * Changes the template type depending on other props provided. - * With `pageHeader` only: Uses `centeredBody` and fills an EuiEmptyPrompt with `pageHeader` info. - * With `children` only: Uses `centeredBody` - * With `pageHeader` and `children`: Uses `centeredContent` - */ - isEmptyState?: boolean; - /** - * Quick creation of EuiSideNav. Hooks up mobile instance too - */ - solutionNav?: KibanaPageTemplateSolutionNavProps; - /** - * Accepts a configuration object, that when provided, ignores pageHeader and children and instead - * displays Agent, Beats, and custom cards to direct users to the right ingest location - */ - noDataConfig?: NoDataPageProps; -}; - -/** @deprecated Use `KibanaPageTemplate` from `@kbn/shared-ux-page-kibana-template`. */ -export const KibanaPageTemplate: FunctionComponent = ({ - template, - className, - children, - solutionNav, - noDataConfig, - ...rest -}) => { - /** - * If passing the custom template of `noDataConfig` - */ - if (noDataConfig && solutionNav) { - return ( - - ); - } - - if (noDataConfig) { - return ( - - ); - } - - if (solutionNav) { - return ( - - ); - } - - return ( - - ); -}; diff --git a/src/plugins/kibana_react/public/page_template/page_template_inner.tsx b/src/plugins/kibana_react/public/page_template/page_template_inner.tsx deleted file mode 100644 index 001cea5c26a23..0000000000000 --- a/src/plugins/kibana_react/public/page_template/page_template_inner.tsx +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React, { FunctionComponent } from 'react'; - -import { EuiEmptyPrompt, EuiPageTemplate_Deprecated as EuiPageTemplate } from '@elastic/eui'; -import { withSolutionNav } from './with_solution_nav'; -import { KibanaPageTemplateProps } from './page_template'; -import { getClasses } from './util'; - -type Props = KibanaPageTemplateProps; - -/** - * A thin wrapper around EuiPageTemplate with a few Kibana specific additions - */ -export const KibanaPageTemplateInner: FunctionComponent = ({ - template, - className, - pageHeader, - children, - isEmptyState, - ...rest -}) => { - /** - * An easy way to create the right content for empty pages - */ - const emptyStateDefaultTemplate = 'centeredBody'; - if (isEmptyState && pageHeader && !children) { - template = template ?? emptyStateDefaultTemplate; - const { iconType, pageTitle, description, rightSideItems } = pageHeader; - pageHeader = undefined; - children = ( - {pageTitle} : undefined} - body={description ?

{description}

: undefined} - actions={rightSideItems} - /> - ); - } else if (isEmptyState && pageHeader && children) { - template = template ?? 'centeredContent'; - } else if (isEmptyState && !pageHeader) { - template = template ?? emptyStateDefaultTemplate; - } - - const classes = getClasses(template, className); - - return ( - - {children} - - ); -}; - -export const KibanaPageTemplateWithSolutionNav = withSolutionNav(KibanaPageTemplateInner); diff --git a/src/plugins/kibana_react/public/page_template/util/constants.ts b/src/plugins/kibana_react/public/page_template/util/constants.ts deleted file mode 100644 index 159a6d0d8d4c1..0000000000000 --- a/src/plugins/kibana_react/public/page_template/util/constants.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 { KibanaPageTemplateProps } from '../page_template'; - -export const NO_DATA_PAGE_MAX_WIDTH = 950; - -export const NO_DATA_PAGE_TEMPLATE_PROPS: KibanaPageTemplateProps = { - restrictWidth: NO_DATA_PAGE_MAX_WIDTH, - template: 'centeredBody', - pageContentProps: { - hasShadow: false, - color: 'transparent', - }, -}; diff --git a/src/plugins/kibana_react/public/page_template/util/index.ts b/src/plugins/kibana_react/public/page_template/util/index.ts index adfefdf834566..06edc43d70d57 100644 --- a/src/plugins/kibana_react/public/page_template/util/index.ts +++ b/src/plugins/kibana_react/public/page_template/util/index.ts @@ -7,4 +7,3 @@ */ export { getClasses } from './presentation'; -export * from './constants'; diff --git a/src/plugins/kibana_react/public/page_template/with_solution_nav.tsx b/src/plugins/kibana_react/public/page_template/with_solution_nav.tsx deleted file mode 100644 index 842573b9d8de4..0000000000000 --- a/src/plugins/kibana_react/public/page_template/with_solution_nav.tsx +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React, { ComponentType, useState } from 'react'; -import classNames from 'classnames'; -import { useIsWithinBreakpoints } from '@elastic/eui'; -import { EuiPageSideBarProps_Deprecated as EuiPageSideBarProps } from '@elastic/eui/src/components/page/page_side_bar'; -import { KibanaPageTemplateSolutionNav, KibanaPageTemplateSolutionNavProps } from './solution_nav'; -import { KibanaPageTemplateProps } from '.'; - -// https://reactjs.org/docs/higher-order-components.html#convention-wrap-the-display-name-for-easy-debugging -function getDisplayName(Component: ComponentType) { - return Component.displayName || Component.name || 'UnnamedComponent'; -} - -type SolutionNavProps = KibanaPageTemplateProps & { - solutionNav: KibanaPageTemplateSolutionNavProps; -}; - -const SOLUTION_NAV_COLLAPSED_KEY = 'solutionNavIsCollapsed'; - -export const withSolutionNav = (WrappedComponent: ComponentType) => { - const WithSolutionNav = (props: SolutionNavProps) => { - const isMediumBreakpoint = useIsWithinBreakpoints(['m']); - const isLargerBreakpoint = useIsWithinBreakpoints(['l', 'xl']); - const [isSideNavOpenOnDesktop, setisSideNavOpenOnDesktop] = useState( - !JSON.parse(String(localStorage.getItem(SOLUTION_NAV_COLLAPSED_KEY))) - ); - const { solutionNav, ...propagatedProps } = props; - const { children, isEmptyState, template } = propagatedProps; - const toggleOpenOnDesktop = () => { - setisSideNavOpenOnDesktop(!isSideNavOpenOnDesktop); - // Have to store it as the opposite of the default we want - localStorage.setItem(SOLUTION_NAV_COLLAPSED_KEY, JSON.stringify(isSideNavOpenOnDesktop)); - }; - const sideBarClasses = classNames( - 'kbnPageTemplate__pageSideBar', - { - 'kbnPageTemplate__pageSideBar--shrink': - isMediumBreakpoint || (isLargerBreakpoint && !isSideNavOpenOnDesktop), - }, - props.pageSideBarProps?.className - ); - - const templateToUse = isEmptyState && !template ? 'centeredContent' : template; - - const pageSideBar = ( - - ); - const pageSideBarProps = { - paddingSize: 'none', - ...props.pageSideBarProps, - className: sideBarClasses, - } as EuiPageSideBarProps; // needed because for some reason 'none' is not recognized as a valid value for paddingSize - return ( - - {children} - - ); - }; - WithSolutionNav.displayName = `WithSolutionNavBar(${getDisplayName(WrappedComponent)})`; - return WithSolutionNav; -}; diff --git a/x-pack/plugins/osquery/public/components/empty_state.tsx b/x-pack/plugins/osquery/public/components/empty_state.tsx index 099e9e22b1f64..18f5afe8eaf5f 100644 --- a/x-pack/plugins/osquery/public/components/empty_state.tsx +++ b/x-pack/plugins/osquery/public/components/empty_state.tsx @@ -9,7 +9,7 @@ import React, { useCallback, useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiButton } from '@elastic/eui'; -import { KibanaPageTemplate } from '@kbn/kibana-react-plugin/public'; +import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; import { INTEGRATIONS_PLUGIN_ID } from '@kbn/fleet-plugin/common'; import { pagePathGetters } from '@kbn/fleet-plugin/public'; import { isModifiedEvent, isLeftClickEvent, useKibana } from '../common/lib/kibana'; diff --git a/x-pack/plugins/osquery/tsconfig.json b/x-pack/plugins/osquery/tsconfig.json index 6cd1086b8a850..d2344a2581df8 100644 --- a/x-pack/plugins/osquery/tsconfig.json +++ b/x-pack/plugins/osquery/tsconfig.json @@ -77,5 +77,6 @@ "@kbn/core-saved-objects-server", "@kbn/monaco", "@kbn/io-ts-utils", + "@kbn/shared-ux-page-kibana-template", ] } From 18555d5dc435c29e51a5b72dff02f5c149a81c17 Mon Sep 17 00:00:00 2001 From: Bruno Mercier Costa <94469565+emrcbrn@users.noreply.github.com> Date: Mon, 25 Sep 2023 16:19:27 +0200 Subject: [PATCH 10/45] [DOCS] Fix typo in Upgrade Assistant docs (#167031) Co-authored-by: James Rodewig --- docs/management/upgrade-assistant.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/management/upgrade-assistant.asciidoc b/docs/management/upgrade-assistant.asciidoc index a44afa4474a7b..ed9093ded2846 100644 --- a/docs/management/upgrade-assistant.asciidoc +++ b/docs/management/upgrade-assistant.asciidoc @@ -26,4 +26,4 @@ The Upgrade assistant pulls information about deprecations from the following so * Elasticsearch deprecation logs * Kibana deprecations API -For more information about the API's the Upgraed assistant provides, refer to <>. +For more information about Upgrade Assistant APIs, refer to <>. From 2dcabd2b82221302615b1a4a09e2a751b51d53c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Mon, 25 Sep 2023 16:33:03 +0100 Subject: [PATCH 11/45] [Profiling] TS fixes (#167129) I ran the ts check on all three projects owned by profiling (`profiling` / `profiling_data_access` / `kbn_profiling-utils`) and all passed now. --------- Co-authored-by: Thomas Watson --- .../components/shared/transaction_action_menu/sections.ts | 2 +- .../shared/transaction_action_menu/transaction_action_menu.tsx | 2 +- x-pack/plugins/observability_shared/public/index.ts | 1 + x-pack/plugins/observability_shared/public/plugin.ts | 1 + x-pack/plugins/profiling/public/index.tsx | 2 -- .../profiling_data_access/server/services/status/index.ts | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts index c17bedeb8635a..04b8f7f41bdf1 100644 --- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts +++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts @@ -12,9 +12,9 @@ import { isEmpty, pickBy } from 'lodash'; import moment from 'moment'; import url from 'url'; import type { InfraLocators } from '@kbn/infra-plugin/common/locators'; -import type { ProfilingLocators } from '@kbn/profiling-plugin/public'; import { LocatorPublic } from '@kbn/share-plugin/common'; import { AllDatasetsLocatorParams } from '@kbn/deeplinks-observability/locators'; +import type { ProfilingLocators } from '@kbn/observability-shared-plugin/public'; import { Environment } from '../../../../common/environment_rt'; import type { Transaction } from '../../../../typings/es_schemas/ui/transaction'; import { getDiscoverHref } from '../links/discover_links/discover_link'; diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.tsx b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.tsx index 162fdf8e90b85..4dcd10a3ea540 100644 --- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.tsx +++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.tsx @@ -18,7 +18,6 @@ import { SectionSubtitle, SectionTitle, } from '@kbn/observability-shared-plugin/public'; -import { ProfilingLocators } from '@kbn/profiling-plugin/public'; import React, { useState } from 'react'; import { useLocation } from 'react-router-dom'; import useAsync from 'react-use/lib/useAsync'; @@ -26,6 +25,7 @@ import { AllDatasetsLocatorParams, ALL_DATASETS_LOCATOR_ID, } from '@kbn/deeplinks-observability/locators'; +import type { ProfilingLocators } from '@kbn/observability-shared-plugin/public'; import { useAnyOfApmParams } from '../../../hooks/use_apm_params'; import { ApmFeatureFlagName } from '../../../../common/apm_feature_flags'; import { Transaction } from '../../../../typings/es_schemas/ui/transaction'; diff --git a/x-pack/plugins/observability_shared/public/index.ts b/x-pack/plugins/observability_shared/public/index.ts index 7e5fc02d0a0b5..a35cdce8f85e1 100644 --- a/x-pack/plugins/observability_shared/public/index.ts +++ b/x-pack/plugins/observability_shared/public/index.ts @@ -10,6 +10,7 @@ export type { ObservabilitySharedPlugin, ObservabilitySharedPluginSetup, ObservabilitySharedPluginStart, + ProfilingLocators, } from './plugin'; export const plugin = () => { return new ObservabilitySharedPlugin(); diff --git a/x-pack/plugins/observability_shared/public/plugin.ts b/x-pack/plugins/observability_shared/public/plugin.ts index 550259184dfb1..faf8990622337 100644 --- a/x-pack/plugins/observability_shared/public/plugin.ts +++ b/x-pack/plugins/observability_shared/public/plugin.ts @@ -34,6 +34,7 @@ export interface ObservabilitySharedStart { export type ObservabilitySharedPluginSetup = ReturnType; export type ObservabilitySharedPluginStart = ReturnType; +export type ProfilingLocators = ObservabilitySharedPluginSetup['locators']['profiling']; export class ObservabilitySharedPlugin implements Plugin { private readonly navigationRegistry = createNavigationRegistry(); diff --git a/x-pack/plugins/profiling/public/index.tsx b/x-pack/plugins/profiling/public/index.tsx index ea9dc15de9927..752635a54290b 100644 --- a/x-pack/plugins/profiling/public/index.tsx +++ b/x-pack/plugins/profiling/public/index.tsx @@ -13,5 +13,3 @@ export function plugin() { } export type { ProfilingPluginSetup, ProfilingPluginStart }; - -export type ProfilingLocators = ProfilingPluginSetup['locators']; diff --git a/x-pack/plugins/profiling_data_access/server/services/status/index.ts b/x-pack/plugins/profiling_data_access/server/services/status/index.ts index 6aea8b1037bd6..31581140b12e0 100644 --- a/x-pack/plugins/profiling_data_access/server/services/status/index.ts +++ b/x-pack/plugins/profiling_data_access/server/services/status/index.ts @@ -12,7 +12,7 @@ import { getSetupState } from '../get_setup_state'; import { RegisterServicesParams } from '../register_services'; import { ProfilingSetupOptions, areResourcesSetup } from '../../../common/setup'; -interface HasSetupParams { +export interface HasSetupParams { soClient: SavedObjectsClientContract; esClient: ElasticsearchClient; spaceId?: string; From 4957d87a66129ee391b6bbaa2ffd3ef554d9bb54 Mon Sep 17 00:00:00 2001 From: "Quynh Nguyen (Quinn)" <43350163+qn895@users.noreply.github.com> Date: Mon, 25 Sep 2023 10:39:15 -0500 Subject: [PATCH 12/45] [Transform] Improve loading behavior of Transform if stats takes too long or is not available (#166320) Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/transform/common/constants.ts | 1 + .../utils/create_stats_unknown_message.ts | 22 ++ .../public/app/common/transform_list.ts | 16 +- .../public/app/common/transform_stats.test.ts | 4 +- .../public/app/common/transform_stats.ts | 4 +- .../app/hooks/use_get_transform_stats.ts | 21 ++ .../public/app/hooks/use_get_transforms.ts | 22 +- .../app/hooks/use_refresh_transform_list.ts | 1 + .../action_delete/delete_action_name.test.tsx | 2 + .../action_delete/delete_action_name.tsx | 74 ++++--- .../action_delete/use_delete_action.tsx | 15 +- .../discover_action_name.test.tsx | 4 +- .../action_discover/discover_action_name.tsx | 4 +- .../reauthorize_action_name.tsx | 1 - .../use_reauthorize_action.tsx | 2 + .../action_reset/reset_action_name.tsx | 76 +++++-- .../action_reset/use_reset_action.tsx | 27 ++- .../schedule_now_action_name.tsx | 10 +- .../use_schedule_now_action.tsx | 5 +- .../action_start/start_action_name.tsx | 16 +- .../action_start/use_start_action.tsx | 4 +- .../action_stop/stop_action_name.tsx | 98 +++++---- .../action_stop/use_stop_action.tsx | 12 +- .../transform_list/expanded_row.test.tsx | 2 +- .../transform_list/expanded_row.tsx | 196 +++++++++++------- .../expanded_row_health_pane.tsx | 9 +- .../transform_list/transform_list.test.tsx | 1 + .../transform_list/transform_list.tsx | 22 +- .../transform_search_bar_filters.tsx | 5 +- .../transform_list/transforms_stats_bar.tsx | 10 +- .../transform_list/use_columns.test.tsx | 2 +- .../components/transform_list/use_columns.tsx | 30 ++- .../transform_management_section.tsx | 47 ++++- x-pack/plugins/transform/tsconfig.json | 1 - 34 files changed, 528 insertions(+), 238 deletions(-) create mode 100644 x-pack/plugins/transform/common/utils/create_stats_unknown_message.ts diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index a1ba2d8277af9..ec26333a834a7 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -43,6 +43,7 @@ export const TRANSFORM_REACT_QUERY_KEYS = { GET_TRANSFORM_NODES: 'transform.get_transform_nodes', GET_TRANSFORM_AUDIT_MESSAGES: 'transform.get_transform_audit_messages', GET_TRANSFORM_STATS: 'transform.get_transform_stats', + GET_TRANSFORMS_STATS: 'transform.get_transforms_stats', GET_TRANSFORMS: 'transform.get_transforms', GET_TRANSFORMS_PREVIEW: 'transform.get_transforms_preview', } as const; diff --git a/x-pack/plugins/transform/common/utils/create_stats_unknown_message.ts b/x-pack/plugins/transform/common/utils/create_stats_unknown_message.ts new file mode 100644 index 0000000000000..9cfe3ccc38ee4 --- /dev/null +++ b/x-pack/plugins/transform/common/utils/create_stats_unknown_message.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export function createNoStatsTooltipMessage({ + actionName, + count = 1, +}: { + actionName: string; + count: number; +}) { + return i18n.translate('xpack.transform.transformList.actionDisabledNoStatsTooltipMessage', { + defaultMessage: + '{actionName} is disabled because the status for {count, plural, one {this transform} other {some transforms}} is unavailable.', + values: { actionName, count }, + }); +} diff --git a/x-pack/plugins/transform/public/app/common/transform_list.ts b/x-pack/plugins/transform/public/app/common/transform_list.ts index c8ddd32f6a8ff..e588ed917958f 100644 --- a/x-pack/plugins/transform/public/app/common/transform_list.ts +++ b/x-pack/plugins/transform/public/app/common/transform_list.ts @@ -20,10 +20,24 @@ export interface TransformListRow { id: TransformId; config: TransformConfigUnion; mode?: string; // added property on client side to allow filtering by this field - stats: TransformStats; + stats?: TransformStats; alerting_rules?: TransformHealthAlertRule[]; } +export type TransformListRowWithStats = TransformListRow & { + stats: TransformStats; +}; + +export function isTransformListRowWithStats( + arg: TransformListRow +): arg is TransformListRowWithStats { + return arg.stats !== undefined; +} + +export function missingTransformStats(items: TransformListRow[]) { + return items.some((i: TransformListRow) => !isTransformListRowWithStats(i)); +} + // The single Action type is not exported as is // from EUI so we use that code to get the single // Action type from the array of actions. diff --git a/x-pack/plugins/transform/public/app/common/transform_stats.test.ts b/x-pack/plugins/transform/public/app/common/transform_stats.test.ts index 974764475eb5f..9213adba45e4d 100644 --- a/x-pack/plugins/transform/public/app/common/transform_stats.test.ts +++ b/x-pack/plugins/transform/public/app/common/transform_stats.test.ts @@ -18,7 +18,7 @@ const getRow = (statsId: string) => { // @ts-expect-error mock data does not actually match TransformListRow type ...(mockTransformListRow as TransformListRow), stats: { - ...(mockTransformStats.transforms as Array).find( + ...(mockTransformStats.transforms as Array>).find( (stats) => stats.id === statsId )!, }, @@ -47,7 +47,7 @@ describe('Transform: Transform stats.', () => { // that will be used by isCompletedBatchTransform() // followed by a call to isCompletedBatchTransform() itself // @ts-expect-error mock data is too loosely typed - const row = mockTransformListRow as TransformListRow; + const row = mockTransformListRow as Required; expect(row.stats.checkpointing.last.checkpoint === 1).toBe(true); expect(row.config.sync === undefined).toBe(true); expect(row.stats.state === TRANSFORM_STATE.STOPPED).toBe(true); diff --git a/x-pack/plugins/transform/public/app/common/transform_stats.ts b/x-pack/plugins/transform/public/app/common/transform_stats.ts index 7763e0712249e..0f7ad5ae98c3f 100644 --- a/x-pack/plugins/transform/public/app/common/transform_stats.ts +++ b/x-pack/plugins/transform/public/app/common/transform_stats.ts @@ -33,7 +33,9 @@ export function isCompletedBatchTransform(item: TransformItem) { // If `checkpoint=1`, `sync` is missing from the config and state is stopped, // then this is a completed batch transform. return ( - item.stats.checkpointing.last.checkpoint === 1 && + item.stats && + item.config && + item.stats.checkpointing?.last.checkpoint === 1 && item.config.sync === undefined && item.stats.state === TRANSFORM_STATE.STOPPED ); diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts index d2b9d32f25853..3c6b329dd880b 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts @@ -35,3 +35,24 @@ export const useGetTransformStats = ( { enabled, refetchInterval } ); }; + +export const useGetTransformsStats = ({ + enabled, + refetchInterval, +}: { + enabled?: boolean; + refetchInterval?: number | false; +}) => { + const { http } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORMS_STATS], + ({ signal }) => + http.get(addInternalBasePath(`transforms/_stats`), { + version: '1', + asSystemRequest: true, + signal, + }), + { enabled, refetchInterval } + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts index f74f7a5774ded..f4afb03c4e4c0 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts @@ -11,14 +11,12 @@ import type { IHttpFetchError } from '@kbn/core-http-browser'; import { isDefined } from '@kbn/ml-is-defined'; import type { GetTransformsResponseSchema } from '../../../common/api_schemas/transforms'; -import type { GetTransformsStatsResponseSchema } from '../../../common/api_schemas/transforms_stats'; import { addInternalBasePath, DEFAULT_REFRESH_INTERVAL_MS, TRANSFORM_REACT_QUERY_KEYS, TRANSFORM_MODE, } from '../../../common/constants'; -import { isTransformStats } from '../../../common/types/transform_stats'; import { type TransformListRow } from '../common'; import { useAppDependencies } from '../app_dependencies'; @@ -55,14 +53,6 @@ export const useGetTransforms = ({ enabled }: UseGetTransformsOptions = {}) => { signal, } ); - const transformStats = await http.get( - addInternalBasePath(`transforms/_stats`), - { - version: '1', - asSystemRequest: true, - signal, - } - ); // There might be some errors with fetching certain transforms // For example, when task exists and is running but the config is deleted @@ -81,21 +71,13 @@ export const useGetTransforms = ({ enabled }: UseGetTransformsOptions = {}) => { } update.transforms = transformConfigs.transforms.reduce((reducedtableRows, config) => { - const stats = transformStats.transforms.find((d) => config.id === d.id); - - // A newly created transform might not have corresponding stats yet. - // If that's the case we just skip the transform and don't add it to the transform list yet. - if (!isTransformStats(stats)) { - return reducedtableRows; - } - - // Table with expandable rows requires `id` on the outer most level + // Table with expandable rows requires `id` on the outermost level reducedtableRows.push({ id: config.id, config, mode: typeof config.sync !== 'undefined' ? TRANSFORM_MODE.CONTINUOUS : TRANSFORM_MODE.BATCH, - stats, + stats: undefined, alerting_rules: config.alerting_rules, }); return reducedtableRows; diff --git a/x-pack/plugins/transform/public/app/hooks/use_refresh_transform_list.ts b/x-pack/plugins/transform/public/app/hooks/use_refresh_transform_list.ts index 651886ba76f7b..3098946157305 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_refresh_transform_list.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_refresh_transform_list.ts @@ -15,6 +15,7 @@ export const useRefreshTransformList = () => { return () => { queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_NODES]); queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORMS]); + queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORMS_STATS]); queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_AUDIT_MESSAGES]); }; }; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.test.tsx index 37daeeb75e138..bec2407ba631c 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.test.tsx @@ -16,9 +16,11 @@ jest.mock('../../../../app_dependencies'); describe('Transform: Transform List Actions ', () => { test('Minimal initialization', () => { const props: DeleteActionNameProps = { + items: [], canDeleteTransform: true, disabled: false, isBulkAction: false, + forceDisable: false, }; const { container } = render(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.tsx index 93e346e6c7a1d..7f68645cb2f18 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.tsx @@ -11,10 +11,12 @@ import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; -import { TransformState, TRANSFORM_STATE } from '../../../../../../common/constants'; -import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; - +import { missingTransformStats } from '../../../../common/transform_list'; +import { createNoStatsTooltipMessage } from '../../../../../../common/utils/create_stats_unknown_message'; +import { TransformCapabilities } from '../../../../../../common/types/capabilities'; import { TransformListRow } from '../../../../common'; +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; +import { TransformState, TRANSFORM_STATE } from '../../../../../../common/constants'; export const deleteActionNameText = i18n.translate( 'xpack.transform.transformList.deleteActionNameText', @@ -24,45 +26,67 @@ export const deleteActionNameText = i18n.translate( ); const transformCanNotBeDeleted = (i: TransformListRow) => + i.stats && !([TRANSFORM_STATE.STOPPED, TRANSFORM_STATE.FAILED] as TransformState[]).includes(i.stats.state); export const isDeleteActionDisabled = (items: TransformListRow[], forceDisable: boolean) => { const disabled = items.some(transformCanNotBeDeleted); - return forceDisable === true || disabled; + + return forceDisable === true || disabled || missingTransformStats(items); }; export interface DeleteActionNameProps { + items: TransformListRow[]; canDeleteTransform: boolean; disabled: boolean; isBulkAction: boolean; + forceDisable: boolean; } +export const getDeleteActionDisabledMessage = ({ + items, + canDeleteTransform, + forceDisable, +}: { + items: TransformListRow[]; + canDeleteTransform: TransformCapabilities['canDeleteTransform']; + forceDisable: boolean; +}) => { + const isBulkAction = items.length > 1; + + if (missingTransformStats(items)) { + return createNoStatsTooltipMessage({ + actionName: deleteActionNameText, + count: items.length, + }); + } + + if (!canDeleteTransform) { + return createCapabilityFailureMessage('canDeleteTransform'); + } + + const disabled = items.some(transformCanNotBeDeleted); + + if (disabled) { + return isBulkAction === true + ? i18n.translate('xpack.transform.transformList.deleteBulkActionDisabledToolTipContent', { + defaultMessage: 'One or more selected transforms must be stopped in order to be deleted.', + }) + : i18n.translate('xpack.transform.transformList.deleteActionDisabledToolTipContent', { + defaultMessage: 'Stop the transform in order to delete it.', + }); + } +}; + export const DeleteActionName: FC = ({ + items, canDeleteTransform, disabled, isBulkAction, + forceDisable, }) => { - const bulkDeleteButtonDisabledText = i18n.translate( - 'xpack.transform.transformList.deleteBulkActionDisabledToolTipContent', - { - defaultMessage: 'One or more selected transforms must be stopped in order to be deleted.', - } - ); - const deleteButtonDisabledText = i18n.translate( - 'xpack.transform.transformList.deleteActionDisabledToolTipContent', - { - defaultMessage: 'Stop the transform in order to delete it.', - } - ); - - if (disabled || !canDeleteTransform) { - let content; - if (disabled) { - content = isBulkAction ? bulkDeleteButtonDisabledText : deleteButtonDisabledText; - } else { - content = createCapabilityFailureMessage('canDeleteTransform'); - } - + const content = getDeleteActionDisabledMessage({ items, canDeleteTransform, forceDisable }); + if (content) { return ( <>{deleteActionNameText} diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx index 5996e271604e3..1942a9a9dc8b7 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx @@ -7,9 +7,10 @@ import React, { useMemo, useState } from 'react'; +import { isTransformListRowWithStats } from '../../../../common/transform_list'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; -import { TransformListAction, TransformListRow } from '../../../../common'; +import type { TransformListAction, TransformListRow } from '../../../../common'; import { useDeleteIndexAndTargetIndex, useDeleteTransforms, @@ -33,7 +34,7 @@ export const useDeleteAction = (forceDisable: boolean) => { const isBulkAction = items.length > 1; const shouldForceDelete = useMemo( - () => items.some((i: TransformListRow) => i.stats.state === TRANSFORM_STATE.FAILED), + () => items.some((i: TransformListRow) => i.stats?.state === TRANSFORM_STATE.FAILED), [items] ); @@ -59,10 +60,10 @@ export const useDeleteAction = (forceDisable: boolean) => { // else, force delete only when the item user picks has failed const forceDelete = isBulkAction ? shouldForceDelete - : items[0] && items[0] && items[0].stats.state === TRANSFORM_STATE.FAILED; + : items[0] && items[0] && items[0].stats?.state === TRANSFORM_STATE.FAILED; deleteTransforms({ - transformsInfo: items.map((i) => ({ + transformsInfo: items.filter(isTransformListRowWithStats).map((i) => ({ id: i.config.id, state: i.stats.state, })), @@ -87,11 +88,15 @@ export const useDeleteAction = (forceDisable: boolean) => { canDeleteTransform, disabled: isDeleteActionDisabled([item], forceDisable), isBulkAction: false, + items: [item], + forceDisable, }} /> ), enabled: (item: TransformListRow) => - !isDeleteActionDisabled([item], forceDisable) && canDeleteTransform, + isTransformListRowWithStats(item) && + !isDeleteActionDisabled([item], forceDisable) && + canDeleteTransform, description: deleteActionNameText, icon: 'trash', type: 'icon', diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/discover_action_name.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/discover_action_name.test.tsx index 4fb0f9e655208..05d804cc9147b 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/discover_action_name.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/discover_action_name.test.tsx @@ -11,16 +11,16 @@ import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render, waitFor, screen } from '@testing-library/react'; -import { TransformListRow } from '../../../../common'; import { isDiscoverActionDisabled, DiscoverActionName } from './discover_action_name'; import transformListRow from '../../../../common/__mocks__/transform_list_row.json'; +import { TransformListRowWithStats } from '../../../../common/transform_list'; jest.mock('../../../../../shared_imports'); jest.mock('../../../../app_dependencies'); // @ts-expect-error mock data is too loosely typed -const item: TransformListRow = transformListRow; +const item: TransformListRowWithStats = transformListRow; describe('Transform: Transform List Actions isDiscoverActionDisabled()', () => { it('should be disabled when more than one item is passed in', () => { diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/discover_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/discover_action_name.tsx index c3d359e648c28..b164dbee25fd2 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/discover_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/discover_action_name.tsx @@ -33,7 +33,7 @@ export const isDiscoverActionDisabled = ( const item = items[0]; // Disable discover action if it's a batch transform and was never started - const stoppedTransform = item.stats.state === TRANSFORM_STATE.STOPPED; + const stoppedTransform = item.stats?.state === TRANSFORM_STATE.STOPPED; const transformProgress = getTransformProgress(item); const isBatchTransform = typeof item.config.sync === 'undefined'; const transformNeverStarted = @@ -52,7 +52,7 @@ export const DiscoverActionName: FC = ({ dataViewExists const item = items[0]; // Disable discover action if it's a batch transform and was never started - const stoppedTransform = item.stats.state === TRANSFORM_STATE.STOPPED; + const stoppedTransform = item.stats?.state === TRANSFORM_STATE.STOPPED; const transformProgress = getTransformProgress(item); const isBatchTransform = typeof item.config.sync === 'undefined'; const transformNeverStarted = diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_name.tsx index ee883a3e7e77b..c0abb4fa5e51c 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_name.tsx @@ -49,7 +49,6 @@ export const ReauthorizeActionName: FC = ({ }) => { const { canStartStopTransform } = useTransformCapabilities(); - // Disable start for batch transforms which have completed. const someNeedsReauthorization = items.some(needsReauthorization); const actionIsDisabled = isReauthorizeActionDisabled( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx index 67e618765e42e..3d216af23db8a 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx @@ -7,6 +7,7 @@ import React, { useMemo, useState } from 'react'; +import { isTransformListRowWithStats } from '../../../../common/transform_list'; import { sortTransformsToReauthorize } from './sort_transforms_to_reauthorize'; import { needsReauthorization } from '../../../../common/reauthorization_utils'; import { useReauthorizeTransforms } from '../../../../hooks/use_reauthorize_transform'; @@ -54,6 +55,7 @@ export const useReauthorizeAction = (forceDisable: boolean, transformNodes: numb ), available: (item: TransformListRow) => needsReauthorization(item), enabled: (item: TransformListRow) => + isTransformListRowWithStats(item) && !isReauthorizeActionDisabled([item], canStartStopTransform, transformNodes), description: reauthorizeActionNameText, icon: 'alert', diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/reset_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/reset_action_name.tsx index 6d5f56d3e7297..0f19701fb0914 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/reset_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/reset_action_name.tsx @@ -11,6 +11,9 @@ import { EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { createNoStatsTooltipMessage } from '../../../../../../common/utils/create_stats_unknown_message'; +import { missingTransformStats } from '../../../../common/transform_list'; +import { TransformCapabilities } from '../../../../../../common/types/capabilities'; import { TransformState, TRANSFORM_STATE } from '../../../../../../common/constants'; import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; @@ -24,45 +27,74 @@ export const resetActionNameText = i18n.translate( ); const transformCanNotBeReseted = (i: TransformListRow) => + i.stats && !([TRANSFORM_STATE.STOPPED, TRANSFORM_STATE.FAILED] as TransformState[]).includes(i.stats.state); export const isResetActionDisabled = (items: TransformListRow[], forceDisable: boolean) => { const disabled = items.some(transformCanNotBeReseted); - return forceDisable === true || disabled; + + return forceDisable === true || disabled || missingTransformStats(items); }; +export const getResetActionDisabledMessage = ({ + items, + canResetTransform, + forceDisable, +}: { + items: TransformListRow[]; + canResetTransform: TransformCapabilities['canResetTransform']; + forceDisable: boolean; +}) => { + const isBulkAction = items.length > 1; + + if (missingTransformStats(items)) { + return createNoStatsTooltipMessage({ + actionName: resetActionNameText, + count: items.length, + }); + } + + if (!canResetTransform) { + return createCapabilityFailureMessage('canResetTransform'); + } + + if (isResetActionDisabled(items, forceDisable)) { + const bulkResetButtonDisabledText = i18n.translate( + 'xpack.transform.transformList.resetBulkActionDisabledToolTipContent', + { + defaultMessage: 'One or more selected transforms must be stopped to be reset.', + } + ); + const resetButtonDisabledText = i18n.translate( + 'xpack.transform.transformList.resetActionDisabledToolTipContent', + { + defaultMessage: 'Stop the transform in order to reset it.', + } + ); + + return isBulkAction ? bulkResetButtonDisabledText : resetButtonDisabledText; + } +}; export interface ResetActionNameProps { + items: TransformListRow[]; + canResetTransform: boolean; disabled: boolean; isBulkAction: boolean; } export const ResetActionName: FC = ({ + items, canResetTransform, disabled, - isBulkAction, }) => { - const bulkResetButtonDisabledText = i18n.translate( - 'xpack.transform.transformList.resetBulkActionDisabledToolTipContent', - { - defaultMessage: 'One or more selected transforms must be stopped to be reset.', - } - ); - const resetButtonDisabledText = i18n.translate( - 'xpack.transform.transformList.resetActionDisabledToolTipContent', - { - defaultMessage: 'Stop the transform in order to reset it.', - } - ); - - if (disabled || !canResetTransform) { - let content; - if (disabled) { - content = isBulkAction ? bulkResetButtonDisabledText : resetButtonDisabledText; - } else { - content = createCapabilityFailureMessage('canResetTransform'); - } + const content = getResetActionDisabledMessage({ + items, + canResetTransform, + forceDisable: disabled, + }); + if (content) { return ( <>{resetActionNameText} diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx index 23a399fdb9086..b00ea69d7e4fd 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx @@ -7,12 +7,21 @@ import React, { useMemo, useState } from 'react'; +import { + isTransformListRowWithStats, + TransformListRowWithStats, +} from '../../../../common/transform_list'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; import { TransformListAction, TransformListRow } from '../../../../common'; import { useTransformCapabilities, useResetTransforms } from '../../../../hooks'; -import { resetActionNameText, isResetActionDisabled, ResetActionName } from './reset_action_name'; +import { + resetActionNameText, + isResetActionDisabled, + ResetActionName, + getResetActionDisabledMessage, +} from './reset_action_name'; export type ResetAction = ReturnType; export const useResetAction = (forceDisable: boolean) => { @@ -24,7 +33,7 @@ export const useResetAction = (forceDisable: boolean) => { const [items, setItems] = useState([]); const shouldForceReset = useMemo( - () => items.some((i: TransformListRow) => i.stats.state === TRANSFORM_STATE.FAILED), + () => items.some((i: TransformListRow) => i.stats?.state === TRANSFORM_STATE.FAILED), [items] ); @@ -34,10 +43,12 @@ export const useResetAction = (forceDisable: boolean) => { setModalVisible(false); resetTransforms({ - transformsInfo: items.map((i) => ({ - id: i.config.id, - state: i.stats.state, - })), + transformsInfo: items + .filter(isTransformListRowWithStats) + .map((i) => ({ + id: i.config.id, + state: i.stats.state, + })), }); }; @@ -56,11 +67,13 @@ export const useResetAction = (forceDisable: boolean) => { canResetTransform, disabled: isResetActionDisabled([item], forceDisable), isBulkAction: false, + items: [item], }} /> ), enabled: (item: TransformListRow) => - !isResetActionDisabled([item], forceDisable) && canResetTransform, + getResetActionDisabledMessage({ items: [item], canResetTransform, forceDisable }) === + undefined, description: resetActionNameText, icon: 'refresh', type: 'icon', diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/schedule_now_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/schedule_now_action_name.tsx index 0c3be1cdad70b..5b4ff6908afdf 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/schedule_now_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/schedule_now_action_name.tsx @@ -11,6 +11,8 @@ import { EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { missingTransformStats } from '../../../../common/transform_list'; +import { createNoStatsTooltipMessage } from '../../../../../../common/utils/create_stats_unknown_message'; import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; import { useTransformCapabilities } from '../../../../hooks'; @@ -35,7 +37,8 @@ export const isScheduleNowActionDisabled = ( !canScheduleNowTransform || completedBatchTransform || items.length === 0 || - transformNodes === 0 + transformNodes === 0 || + missingTransformStats(items) ); }; @@ -92,6 +95,11 @@ export const ScheduleNowActionName: FC = ({ content = createCapabilityFailureMessage('canScheduleNowTransform'); } else if (completedBatchTransform) { content = completedBatchTransformMessage; + } else if (missingTransformStats(items)) { + content = createNoStatsTooltipMessage({ + actionName: scheduleNowActionNameText, + count: items.length, + }); } } diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx index a13d3da89f677..e5d330eb9ba28 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx @@ -7,6 +7,7 @@ import React, { useMemo } from 'react'; +import { isTransformListRowWithStats } from '../../../../common/transform_list'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; import { useTransformCapabilities } from '../../../../hooks'; @@ -33,8 +34,10 @@ export const useScheduleNowAction = (forceDisable: boolean, transformNodes: numb transformNodes={transformNodes} /> ), - available: (item: TransformListRow) => item.stats.state === TRANSFORM_STATE.STARTED, + available: (item: TransformListRow) => + isTransformListRowWithStats(item) ? item.stats.state === TRANSFORM_STATE.STARTED : true, enabled: (item: TransformListRow) => + isTransformListRowWithStats(item) && !isScheduleNowActionDisabled([item], canScheduleNowTransform, transformNodes), description: scheduleNowActionNameText, icon: 'play', diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.tsx index c50c83d25edc5..22ddbf1d12c3d 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.tsx @@ -9,6 +9,8 @@ import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; +import { createNoStatsTooltipMessage } from '../../../../../../common/utils/create_stats_unknown_message'; +import { missingTransformStats } from '../../../../common/transform_list'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; @@ -31,7 +33,7 @@ export const isStartActionDisabled = ( const completedBatchTransform = items.some((i: TransformListRow) => isCompletedBatchTransform(i)); // Disable start action if one of the transforms is already started or trying to restart will throw error const startedTransform = items.some( - (i: TransformListRow) => i.stats.state === TRANSFORM_STATE.STARTED + (i: TransformListRow) => i.stats?.state === TRANSFORM_STATE.STARTED ); return ( @@ -39,7 +41,8 @@ export const isStartActionDisabled = ( completedBatchTransform || startedTransform || items.length === 0 || - transformNodes === 0 + transformNodes === 0 || + missingTransformStats(items) ); }; @@ -58,9 +61,9 @@ export const StartActionName: FC = ({ // Disable start for batch transforms which have completed. const completedBatchTransform = items.some((i: TransformListRow) => isCompletedBatchTransform(i)); - // Disable start action if one of the transforms is already started or trying to restart will throw error + // Disable if one of the transforms is already started or trying to restart will throw error const startedTransform = items.some( - (i: TransformListRow) => i.stats.state === TRANSFORM_STATE.STARTED + (i: TransformListRow) => i.stats?.state === TRANSFORM_STATE.STARTED ); let startedTransformMessage; @@ -107,6 +110,11 @@ export const StartActionName: FC = ({ content = completedBatchTransformMessage; } else if (startedTransform) { content = startedTransformMessage; + } else if (missingTransformStats(items)) { + content = createNoStatsTooltipMessage({ + actionName: startActionNameText, + count: items.length, + }); } } diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx index 168174730b706..3724e53cf69b8 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx @@ -7,6 +7,7 @@ import React, { useMemo, useState } from 'react'; +import { isTransformListRowWithStats } from '../../../../common/transform_list'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; import { TransformListAction, TransformListRow } from '../../../../common'; @@ -46,7 +47,8 @@ export const useStartAction = (forceDisable: boolean, transformNodes: number) => transformNodes={transformNodes} /> ), - available: (item: TransformListRow) => item.stats.state === TRANSFORM_STATE.STOPPED, + available: (item: TransformListRow) => + isTransformListRowWithStats(item) ? item.stats.state === TRANSFORM_STATE.STOPPED : true, enabled: (item: TransformListRow) => !isStartActionDisabled([item], canStartStopTransform, transformNodes), description: startActionNameText, diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.tsx index e5bc1425cdd99..b2a079a425273 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.tsx @@ -9,6 +9,12 @@ import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; +import { TransformCapabilities } from '../../../../../../common/types/capabilities'; +import { + isTransformListRowWithStats, + missingTransformStats, +} from '../../../../common/transform_list'; +import { createNoStatsTooltipMessage } from '../../../../../../common/utils/create_stats_unknown_message'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; @@ -22,6 +28,46 @@ export const stopActionNameText = i18n.translate( } ); +export const getStopActionDisabledMessage = ({ + items, + capabilities, +}: { + items: TransformListRow[]; + capabilities: TransformCapabilities; +}) => { + const isBulkAction = items.length > 1; + + const { canStartStopTransform } = capabilities; + + if (missingTransformStats(items)) { + return createNoStatsTooltipMessage({ + actionName: stopActionNameText, + count: items.length, + }); + } + + // Disable stop action if one of the transforms is stopped already + const stoppedTransform = items.some( + (i: TransformListRow) => + isTransformListRowWithStats(i) && i.stats.state === TRANSFORM_STATE.STOPPED + ); + + if (!canStartStopTransform) { + return createCapabilityFailureMessage('canStartStopTransform'); + } + + if (stoppedTransform) { + return isBulkAction === true + ? i18n.translate('xpack.transform.transformList.stoppedTransformBulkToolTip', { + defaultMessage: 'One or more transforms are already stopped.', + }) + : i18n.translate('xpack.transform.transformList.stoppedTransformToolTip', { + defaultMessage: '{transformId} is already stopped.', + values: { transformId: items[0] && items[0].config.id }, + }); + } +}; + export const isStopActionDisabled = ( items: TransformListRow[], canStartStopTransform: boolean, @@ -29,10 +75,15 @@ export const isStopActionDisabled = ( ) => { // Disable stop action if one of the transforms is stopped already const stoppedTransform = items.some( - (i: TransformListRow) => i.stats.state === TRANSFORM_STATE.STOPPED + (i: TransformListRow) => i.stats?.state === TRANSFORM_STATE.STOPPED ); - return forceDisable === true || !canStartStopTransform || stoppedTransform === true; + return ( + forceDisable === true || + !canStartStopTransform || + stoppedTransform === true || + missingTransformStats(items) + ); }; export interface StopActionNameProps { @@ -40,42 +91,15 @@ export interface StopActionNameProps { forceDisable?: boolean; } export const StopActionName: FC = ({ items, forceDisable }) => { - const isBulkAction = items.length > 1; - const { canStartStopTransform } = useTransformCapabilities(); - - // Disable stop action if one of the transforms is stopped already - const stoppedTransform = items.some( - (i: TransformListRow) => i.stats.state === TRANSFORM_STATE.STOPPED - ); - - let stoppedTransformMessage; - if (isBulkAction === true) { - stoppedTransformMessage = i18n.translate( - 'xpack.transform.transformList.stoppedTransformBulkToolTip', - { - defaultMessage: 'One or more transforms are already stopped.', - } - ); - } else { - stoppedTransformMessage = i18n.translate( - 'xpack.transform.transformList.stoppedTransformToolTip', - { - defaultMessage: '{transformId} is already stopped.', - values: { transformId: items[0] && items[0].config.id }, - } - ); - } - - if (!canStartStopTransform || stoppedTransform) { + const capabilities = useTransformCapabilities(); + // Disable transforms if stats does not exist + const stoppedTransformMessage = getStopActionDisabledMessage({ + items, + capabilities, + }); + if (forceDisable || stoppedTransformMessage) { return ( - + <>{stopActionNameText} ); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx index e410704341177..36ec5139d14ee 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx @@ -6,6 +6,7 @@ */ import React, { useCallback, useMemo, useState } from 'react'; +import { isTransformListRowWithStats } from '../../../../common/transform_list'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; import { TransformListAction, TransformListRow } from '../../../../common'; import { useTransformCapabilities, useStopTransforms } from '../../../../hooks'; @@ -30,13 +31,16 @@ export const useStopAction = (forceDisable: boolean) => { const stopAndCloseModal = useCallback( (transformSelection: TransformListRow[]) => { setModalVisible(false); - stopTransforms(transformSelection.map((t) => ({ id: t.id, state: t.stats.state }))); + stopTransforms( + transformSelection.map((t) => ({ id: t.id, state: t.stats ? t.stats.state : 'waiting' })) + ); }, [stopTransforms] ); const clickHandler = useCallback( - (i: TransformListRow) => stopTransforms([{ id: i.id, state: i.stats.state }]), + (t: TransformListRow) => + stopTransforms([{ id: t.id, state: t.stats ? t.stats.state : 'waiting' }]), [stopTransforms] ); @@ -45,8 +49,10 @@ export const useStopAction = (forceDisable: boolean) => { name: (item: TransformListRow) => ( ), - available: (item: TransformListRow) => item.stats.state !== TRANSFORM_STATE.STOPPED, + available: (item: TransformListRow) => + isTransformListRowWithStats(item) ? item.stats.state !== TRANSFORM_STATE.STOPPED : true, enabled: (item: TransformListRow) => + isTransformListRowWithStats(item) && !isStopActionDisabled([item], canStartStopTransform, forceDisable), description: stopActionNameText, icon: 'stop', diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx index f8b55dbbeda3c..370d7c2da05d5 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx @@ -38,7 +38,7 @@ describe('Transform: Transform List ', () => { render( - + ); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.tsx index f4766da492f67..c43e3d096f32b 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.tsx @@ -9,14 +9,23 @@ import React, { FC, useMemo } from 'react'; import { css } from '@emotion/react'; import moment from 'moment-timezone'; -import { EuiButtonEmpty, EuiTabbedContent } from '@elastic/eui'; +import { + EuiButtonEmpty, + EuiLoadingSpinner, + EuiTabbedContent, + EuiFlexGroup, + useEuiTheme, + EuiCallOut, + EuiFlexItem, +} from '@elastic/eui'; -import { Optional } from '@kbn/utility-types'; import { i18n } from '@kbn/i18n'; import { formatHumanReadableDateTimeSeconds } from '@kbn/ml-date-utils'; import { stringHash } from '@kbn/ml-string-hash'; import { isDefined } from '@kbn/ml-is-defined'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { isTransformListRowWithStats } from '../../../../common/transform_list'; import { useIsServerless } from '../../../../serverless_context'; import { TransformHealthAlertRule } from '../../../../../../common/types/alerting'; @@ -42,39 +51,66 @@ type Item = SectionItem; interface Props { item: TransformListRow; onAlertEdit: (alertRule: TransformHealthAlertRule) => void; + transformsStatsLoading: boolean; } -type StateValues = Optional; +const NoStatsFallbackTabContent = ({ + transformsStatsLoading, +}: { + transformsStatsLoading: boolean; +}) => { + const { euiTheme } = useEuiTheme(); -export const ExpandedRow: FC = ({ item, onAlertEdit }) => { - const hideNodeInfo = useIsServerless(); + const content = transformsStatsLoading ? ( + + ) : ( + + + } + /> + + ); + return ( + + {content} + + ); +}; - const stateValues: StateValues = { ...item.stats }; - delete stateValues.stats; - delete stateValues.checkpointing; +export const ExpandedRow: FC = ({ item, onAlertEdit, transformsStatsLoading }) => { + const hideNodeInfo = useIsServerless(); const stateItems: Item[] = []; - stateItems.push( - { - title: 'ID', - description: item.id, - }, - { + stateItems.push({ + title: 'ID', + description: item.id, + }); + if (isTransformListRowWithStats(item)) { + stateItems.push({ title: 'state', description: item.stats.state, - } - ); - if (!hideNodeInfo && item.stats.node !== undefined) { - stateItems.push({ - title: 'node.name', - description: item.stats.node.name, - }); - } - if (item.stats.health !== undefined) { - stateItems.push({ - title: 'health', - description: , }); + + if (!hideNodeInfo && item.stats.node !== undefined) { + stateItems.push({ + title: 'node.name', + description: item.stats.node.name, + }); + } + if (item.stats.health !== undefined) { + stateItems.push({ + title: 'health', + description: , + }); + } } const state: SectionConfig = { @@ -137,69 +173,71 @@ export const ExpandedRow: FC = ({ item, onAlertEdit }) => { }; const checkpointingItems: Item[] = []; - if (item.stats.checkpointing.changes_last_detected_at !== undefined) { - checkpointingItems.push({ - title: 'changes_last_detected_at', - description: formatHumanReadableDateTimeSeconds( - item.stats.checkpointing.changes_last_detected_at - ), - }); - } - - if (item.stats.checkpointing.last !== undefined) { - checkpointingItems.push({ - title: 'last.checkpoint', - description: item.stats.checkpointing.last.checkpoint, - }); - if (item.stats.checkpointing.last.timestamp_millis !== undefined) { + if (isTransformListRowWithStats(item)) { + if (item.stats.checkpointing.changes_last_detected_at !== undefined) { checkpointingItems.push({ - title: 'last.timestamp', + title: 'changes_last_detected_at', description: formatHumanReadableDateTimeSeconds( - item.stats.checkpointing.last.timestamp_millis + item.stats.checkpointing.changes_last_detected_at ), }); + } + + if (item.stats.checkpointing.last !== undefined) { checkpointingItems.push({ - title: 'last.timestamp_millis', - description: item.stats.checkpointing.last.timestamp_millis, + title: 'last.checkpoint', + description: item.stats.checkpointing.last.checkpoint, }); + if (item.stats.checkpointing.last.timestamp_millis !== undefined) { + checkpointingItems.push({ + title: 'last.timestamp', + description: formatHumanReadableDateTimeSeconds( + item.stats.checkpointing.last.timestamp_millis + ), + }); + checkpointingItems.push({ + title: 'last.timestamp_millis', + description: item.stats.checkpointing.last.timestamp_millis, + }); + } } - } - - if (item.stats.checkpointing.last_search_time !== undefined) { - checkpointingItems.push({ - title: 'last_search_time', - description: formatHumanReadableDateTimeSeconds(item.stats.checkpointing.last_search_time), - }); - } - if (item.stats.checkpointing.next !== undefined) { - checkpointingItems.push({ - title: 'next.checkpoint', - description: item.stats.checkpointing.next.checkpoint, - }); - if (item.stats.checkpointing.next.checkpoint_progress !== undefined) { + if (item.stats.checkpointing.last_search_time !== undefined) { checkpointingItems.push({ - title: 'next.checkpoint_progress.total_docs', - description: item.stats.checkpointing.next.checkpoint_progress.total_docs, + title: 'last_search_time', + description: formatHumanReadableDateTimeSeconds(item.stats.checkpointing.last_search_time), }); + } + + if (item.stats.checkpointing.next !== undefined) { checkpointingItems.push({ - title: 'next.checkpoint_progress.docs_remaining', - description: item.stats.checkpointing.next.checkpoint_progress.docs_remaining, + title: 'next.checkpoint', + description: item.stats.checkpointing.next.checkpoint, }); + if (item.stats.checkpointing.next.checkpoint_progress !== undefined) { + checkpointingItems.push({ + title: 'next.checkpoint_progress.total_docs', + description: item.stats.checkpointing.next.checkpoint_progress.total_docs, + }); + checkpointingItems.push({ + title: 'next.checkpoint_progress.docs_remaining', + description: item.stats.checkpointing.next.checkpoint_progress.docs_remaining, + }); + checkpointingItems.push({ + title: 'next.checkpoint_progress.percent_complete', + description: item.stats.checkpointing.next.checkpoint_progress.percent_complete, + }); + } + } + + if (item.stats.checkpointing.operations_behind !== undefined) { checkpointingItems.push({ - title: 'next.checkpoint_progress.percent_complete', - description: item.stats.checkpointing.next.checkpoint_progress.percent_complete, + title: 'operations_behind', + description: item.stats.checkpointing.operations_behind, }); } } - if (item.stats.checkpointing.operations_behind !== undefined) { - checkpointingItems.push({ - title: 'operations_behind', - description: item.stats.checkpointing.operations_behind, - }); - } - const alertRuleItems: Item[] | undefined = item.alerting_rules?.map((rule) => { return { title: ( @@ -236,9 +274,11 @@ export const ExpandedRow: FC = ({ item, onAlertEdit }) => { const stats: SectionConfig = { title: 'Stats', - items: Object.entries(item.stats.stats).map((s) => { - return { title: s[0].toString(), description: getItemDescription(s[1]) }; - }), + items: item.stats + ? Object.entries(item.stats.stats).map((s) => { + return { title: s[0].toString(), description: getItemDescription(s[1]) }; + }) + : [], position: 'left', }; @@ -275,8 +315,10 @@ export const ExpandedRow: FC = ({ item, onAlertEdit }) => { defaultMessage: 'Stats', } ), - content: ( + content: item.stats ? ( + ) : ( + ), }, { @@ -285,7 +327,7 @@ export const ExpandedRow: FC = ({ item, onAlertEdit }) => { name: 'JSON', content: , }, - ...(item.stats.health + ...(item.stats?.health ? [ { id: `transform-health-tab-${tabId}`, diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_health_pane.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_health_pane.tsx index 0e8ab94dc2086..3a088d5a9b273 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_health_pane.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_health_pane.tsx @@ -12,14 +12,15 @@ import { formatDate, EuiPanel, EuiSpacer, EuiInMemoryTable } from '@elastic/eui' import { i18n } from '@kbn/i18n'; import { TIME_FORMAT } from '../../../../../../common/constants'; -import type { TransformHealthIssue } from '../../../../../../common/types/transform_stats'; - -import { TransformListRow } from '../../../../common'; +import type { + TransformHealthIssue, + TransformStats, +} from '../../../../../../common/types/transform_stats'; import { TransformHealthColoredDot } from './transform_health_colored_dot'; interface ExpandedRowHealthPaneProps { - health: TransformListRow['stats']['health']; + health: TransformStats['health']; } export const ExpandedRowHealthPane: FC = ({ health }) => { diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx index fc4bf0e24d14d..e3f98beea9e7e 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx @@ -39,6 +39,7 @@ describe('Transform: Transform List ', () => { transformNodes={1} transforms={[]} transformsLoading={false} + transformsStatsLoading={false} /> diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx index 2e0106afc0e92..a55253a08b5eb 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx @@ -70,12 +70,19 @@ type ItemIdToExpandedRowMap = Record; function getItemIdToExpandedRowMap( itemIds: TransformId[], transforms: TransformListRow[], - onAlertEdit: (alertRule: TransformHealthAlertRule) => void + onAlertEdit: (alertRule: TransformHealthAlertRule) => void, + transformsStatsLoading: boolean ): ItemIdToExpandedRowMap { return itemIds.reduce((m: ItemIdToExpandedRowMap, transformId: TransformId) => { const item = transforms.find((transform) => transform.config.id === transformId); if (item !== undefined) { - m[transformId] = ; + m[transformId] = ( + + ); } return m; }, {} as ItemIdToExpandedRowMap); @@ -87,6 +94,7 @@ interface TransformListProps { transformNodes: number; transforms: TransformListRow[]; transformsLoading: boolean; + transformsStatsLoading: boolean; } export const TransformList: FC = ({ @@ -95,6 +103,7 @@ export const TransformList: FC = ({ transformNodes, transforms, transformsLoading, + transformsStatsLoading, }) => { const refreshTransformList = useRefreshTransformList(); const { setEditAlertRule } = useAlertRuleFlyout(); @@ -126,7 +135,8 @@ export const TransformList: FC = ({ expandedRowItemIds, setExpandedRowItemIds, transformNodes, - transformSelection + transformSelection, + transformsStatsLoading ); const searchError = query?.error ? query?.error.message : undefined; @@ -166,7 +176,8 @@ export const TransformList: FC = ({ const itemIdToExpandedRowMap = getItemIdToExpandedRowMap( expandedRowItemIds, transforms, - setEditAlertRule + setEditAlertRule, + transformsStatsLoading ); const bulkActionMenuItems = [ @@ -235,6 +246,7 @@ export const TransformList: FC = ({ canResetTransform={capabilities.canResetTransform} disabled={isResetActionDisabled(transformSelection, false)} isBulkAction={true} + items={transformSelection} />
, @@ -247,6 +259,8 @@ export const TransformList: FC = ({ canDeleteTransform={capabilities.canDeleteTransform} disabled={isDeleteActionDisabled(transformSelection, false)} isBulkAction={true} + items={transformSelection} + forceDisable={false} />
, diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_search_bar_filters.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_search_bar_filters.tsx index 5a2df943e9a54..637f32558cb41 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_search_bar_filters.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_search_bar_filters.tsx @@ -106,9 +106,12 @@ export const filterTransforms = (transforms: TransformListRow[], clauses: Clause // filter other clauses, i.e. the mode and status filters if (c.type !== 'is' && Array.isArray(c.value)) { // the status value is an array of string(s) e.g. ['failed', 'stopped'] - ts = transforms.filter((transform) => (c.value as Value[]).includes(transform.stats.state)); + ts = transforms.filter( + (transform) => transform.stats && (c.value as Value[]).includes(transform.stats.state) + ); } else { ts = transforms.filter((transform) => { + if (!transform.stats) return false; if (c.type === 'field' && c.field === 'health') { return transform.stats.health?.status === c.value; } diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx index 79f6321c2419f..ea85f705e46ef 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx @@ -94,10 +94,12 @@ function createTranformStats( transformStats.batch.value++; } - if (transform.stats.state === TRANSFORM_STATE.FAILED) { - failedTransforms++; - } else if (transform.stats.state === TRANSFORM_STATE.STARTED) { - startedTransforms++; + if (transform.stats) { + if (transform.stats.state === TRANSFORM_STATE.FAILED) { + failedTransforms++; + } else if (transform.stats.state === TRANSFORM_STATE.STARTED) { + startedTransforms++; + } } }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.test.tsx index 87f550e433bc2..e49df35b42a55 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.test.tsx @@ -20,7 +20,7 @@ describe('Transform: Job List Columns', () => { const wrapper: FC = ({ children }) => ( {children} ); - const { result, waitForNextUpdate } = renderHook(() => useColumns([], () => {}, 1, []), { + const { result, waitForNextUpdate } = renderHook(() => useColumns([], () => {}, 1, [], false), { wrapper, }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.tsx index 2ae8edf30a1de..fb578ec06aa3c 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.tsx @@ -22,6 +22,7 @@ import { EuiToolTip, RIGHT_ALIGNMENT, EuiIcon, + EuiLoadingSpinner, } from '@elastic/eui'; import { useTransformCapabilities } from '../../../../hooks'; @@ -46,12 +47,20 @@ const TRANSFORM_INSUFFICIENT_PERMISSIONS_MSG = i18n.translate( defaultMessage: 'This transform was created with insufficient permissions.', } ); + +const StatsUnknown = () => ( + + + +); export const useColumns = ( expandedRowItemIds: TransformId[], setExpandedRowItemIds: React.Dispatch>, transformNodes: number, - transformSelection: TransformListRow[] + transformSelection: TransformListRow[], + transformsStatsLoading: boolean ) => { + const NoStatsFallbackComponent = transformsStatsLoading ? EuiLoadingSpinner : StatsUnknown; const { canStartStopTransform } = useTransformCapabilities(); const { actions, modals } = useActions({ @@ -239,10 +248,14 @@ export const useColumns = ( { name: i18n.translate('xpack.transform.status', { defaultMessage: 'Status' }), 'data-test-subj': 'transformListColumnStatus', - sortable: (item: TransformListRow) => item.stats.state, + sortable: (item: TransformListRow) => item.stats?.state, truncateText: true, render(item: TransformListRow) { - return ; + return item.stats ? ( + + ) : ( + + ); }, width: '100px', }, @@ -271,6 +284,7 @@ export const useColumns = ( if (progress === undefined && isBatchTransform === true) { return null; } + if (!item.stats) return ; return ( @@ -292,7 +306,7 @@ export const useColumns = ( )} - {!isBatchTransform && ( + {!isBatchTransform && item.stats && ( <> {/* If not stopped, failed or waiting show the animated progress bar */} @@ -321,10 +335,14 @@ export const useColumns = ( { name: i18n.translate('xpack.transform.health', { defaultMessage: 'Health' }), 'data-test-subj': 'transformListColumnHealth', - sortable: (item: TransformListRow) => item.stats.health.status, + sortable: (item: TransformListRow) => item.stats?.health.status, truncateText: true, render(item: TransformListRow) { - return ; + return item.stats ? ( + + ) : ( + + ); }, width: '100px', }, 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 cce3128b3f3d0..858954976cf82 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 @@ -21,6 +21,9 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { IHttpFetchError } from '@kbn/core-http-browser'; +import type { TransformListRow } from '../../common'; +import { isTransformStats } from '../../../../common/types/transform_stats'; +import { useGetTransformsStats } from '../../hooks/use_get_transform_stats'; import { useIsServerless } from '../../serverless_context'; import { needsReauthorization } from '../../common/reauthorization_utils'; import { TRANSFORM_STATE } from '../../../../common/constants'; @@ -85,13 +88,37 @@ export const TransformManagement: FC = () => { const { isInitialLoading: transformsInitialLoading, - isLoading: transformsLoading, + isLoading: transformsWithoutStatsLoading, error: transformsErrorMessage, - data: { transforms, transformIdsWithoutConfig }, + data: { transforms: transformsWithoutStats, transformIdsWithoutConfig }, } = useGetTransforms({ enabled: !transformNodesInitialLoading && (transformNodes > 0 || hideNodeInfo), }); + const { + isLoading: transformsStatsLoading, + error: transformsStatsErrorMessage, + data: transformsStats, + } = useGetTransformsStats({ + enabled: !transformNodesInitialLoading && (transformNodes > 0 || hideNodeInfo), + }); + + const transforms: TransformListRow[] = useMemo(() => { + if (!transformsStats) return transformsWithoutStats; + + return transformsWithoutStats.map((t) => { + const stats = transformsStats.transforms.find((d) => t.config.id === d.id); + + // A newly created transform might not have corresponding stats yet. + // If that's the case we just skip the transform and don't add it to the transform list yet. + if (!isTransformStats(stats)) { + return t; + } + + return { ...t, stats }; + }); + }, [transformsStats, transformsWithoutStats]); + const isInitialLoading = transformNodesInitialLoading || transformsInitialLoading; const { canStartStopTransform } = useTransformCapabilities(); @@ -219,6 +246,17 @@ export const TransformManagement: FC = () => { errorMessage={transformsErrorMessage} /> )} + {transformsStatsErrorMessage !== null ? ( + + } + errorMessage={transformsStatsErrorMessage} + /> + ) : null} @@ -272,11 +310,12 @@ export const TransformManagement: FC = () => { ) : null} {(transformNodes > 0 || transforms.length > 0) && ( )} diff --git a/x-pack/plugins/transform/tsconfig.json b/x-pack/plugins/transform/tsconfig.json index 52e0747cc1fb9..7b41f101c15c1 100644 --- a/x-pack/plugins/transform/tsconfig.json +++ b/x-pack/plugins/transform/tsconfig.json @@ -40,7 +40,6 @@ "@kbn/std", "@kbn/es-query", "@kbn/ml-agg-utils", - "@kbn/utility-types", "@kbn/ml-string-hash", "@kbn/ui-theme", "@kbn/field-types", From 13e5c076d53d723c423645afeeefa6eaded9cf02 Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Mon, 25 Sep 2023 17:39:34 +0200 Subject: [PATCH 13/45] [Observability AI Assistant] ES|QL query generation (#166041) Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../common/types.ts | 28 +- .../public/components/chat/chat_body.tsx | 4 + .../public/components/chat/chat_item.tsx | 8 +- ...chat_item_content_inline_prompt_editor.tsx | 5 +- .../components/chat/chat_timeline.stories.tsx | 1 + .../public/components/chat/chat_timeline.tsx | 4 + .../components/chat/function_list_popover.tsx | 20 +- .../public/components/chat/types.ts | 23 + .../public/components/insight/insight.tsx | 8 +- .../insight/insight_base.stories.tsx | 1 + .../message_panel/esql_code_block.stories.tsx | 34 ++ .../message_panel/esql_code_block.tsx | 77 +++ .../message_panel/message_panel.stories.tsx | 26 +- .../components/message_panel/message_text.tsx | 47 +- .../public/functions/esql.ts | 536 ++++++++++++++++++ .../public/functions/index.ts | 19 +- .../public/functions/recall.ts | 44 +- .../public/hooks/use_timeline.test.ts | 1 + .../public/hooks/use_timeline.ts | 78 ++- .../public/service/create_chat_service.ts | 9 +- .../service/get_assistant_setup_message.ts | 6 +- .../public/types.ts | 12 +- .../server/plugin.ts | 2 +- .../server/routes/chat/route.ts | 56 +- .../server/routes/functions/route.ts | 25 +- .../server/service/client/index.ts | 50 +- .../server/service/index.ts | 37 +- .../server/service/kb_service/index.ts | 60 +- .../server/service/kb_service/kb_docs/lens.ts | 10 +- .../server/service/util/get_category_query.ts | 38 ++ 30 files changed, 1137 insertions(+), 132 deletions(-) create mode 100644 x-pack/plugins/observability_ai_assistant/public/components/chat/types.ts create mode 100644 x-pack/plugins/observability_ai_assistant/public/components/message_panel/esql_code_block.stories.tsx create mode 100644 x-pack/plugins/observability_ai_assistant/public/components/message_panel/esql_code_block.tsx create mode 100644 x-pack/plugins/observability_ai_assistant/public/functions/esql.ts create mode 100644 x-pack/plugins/observability_ai_assistant/server/service/util/get_category_query.ts diff --git a/x-pack/plugins/observability_ai_assistant/common/types.ts b/x-pack/plugins/observability_ai_assistant/common/types.ts index b14137dbaebf5..690b931271bb6 100644 --- a/x-pack/plugins/observability_ai_assistant/common/types.ts +++ b/x-pack/plugins/observability_ai_assistant/common/types.ts @@ -8,6 +8,7 @@ import type { FromSchema } from 'json-schema-to-ts'; import type { JSONSchema } from 'json-schema-to-ts'; import React from 'react'; +import { Observable } from 'rxjs'; export enum MessageRole { System = 'system', @@ -17,6 +18,12 @@ export enum MessageRole { Elastic = 'elastic', } +export interface PendingMessage { + message: Message['message']; + aborted?: boolean; + error?: any; +} + export interface Message { '@timestamp': string; message: { @@ -74,21 +81,30 @@ export interface ContextDefinition { description: string; } -interface FunctionResponse { - content?: any; - data?: any; +type FunctionResponse = + | { + content?: any; + data?: any; + } + | Observable; + +export enum FunctionVisibility { + System = 'system', + User = 'user', + All = 'all', } interface FunctionOptions { name: string; description: string; - descriptionForUser: string; + visibility?: FunctionVisibility; + descriptionForUser?: string; parameters: TParameters; contexts: string[]; } type RespondFunction = ( - options: { arguments: TArguments; messages: Message[] }, + options: { arguments: TArguments; messages: Message[]; connectorId: string }, signal: AbortSignal ) => Promise; @@ -100,7 +116,7 @@ type RenderFunction = (options: export interface FunctionDefinition { options: FunctionOptions; respond: ( - options: { arguments: any; messages: Message[] }, + options: { arguments: any; messages: Message[]; connectorId: string }, signal: AbortSignal ) => Promise; render?: RenderFunction; diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.tsx index 8a6227829c855..f49ebe8c62b92 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.tsx @@ -189,6 +189,10 @@ export function ChatBody({ onFeedback={timeline.onFeedback} onRegenerate={timeline.onRegenerate} onStopGenerating={timeline.onStopGenerating} + onActionClick={(payload) => { + setStickToBottom(true); + return timeline.onActionClick(payload); + }} />
diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item.tsx index b3fa93d1ec522..7ec1084a26b22 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item.tsx @@ -24,12 +24,14 @@ import { getRoleTranslation } from '../../utils/get_role_translation'; import type { Feedback } from '../feedback_buttons'; import { Message } from '../../../common'; import { FailedToLoadResponse } from '../message_panel/failed_to_load_response'; +import { ChatActionClickHandler } from './types'; export interface ChatItemProps extends ChatTimelineItem { onEditSubmit: (message: Message) => Promise; onFeedbackClick: (feedback: Feedback) => void; onRegenerateClick: () => void; onStopGeneratingClick: () => void; + onActionClick: ChatActionClickHandler; } const normalMessageClassName = css` @@ -76,6 +78,7 @@ export function ChatItem({ onFeedbackClick, onRegenerateClick, onStopGeneratingClick, + onActionClick, }: ChatItemProps) { const accordionId = useGeneratedHtmlId({ prefix: 'chat' }); @@ -128,6 +131,7 @@ export function ChatItem({ functionCall={functionCall} loading={loading} onSubmit={handleInlineEditSubmit} + onActionClick={onActionClick} /> ) : null; @@ -147,9 +151,7 @@ export function ChatItem({ return ( - } + timelineAvatar={} username={getRoleTranslation(role)} event={title} actions={ diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item_content_inline_prompt_editor.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item_content_inline_prompt_editor.tsx index d017d7d65fc90..df57f069d91d1 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item_content_inline_prompt_editor.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item_content_inline_prompt_editor.tsx @@ -9,6 +9,7 @@ import React from 'react'; import { MessageText } from '../message_panel/message_text'; import { ChatPromptEditor } from './chat_prompt_editor'; import { MessageRole, type Message } from '../../../common'; +import { ChatActionClickHandler } from './types'; interface Props { content: string | undefined; @@ -22,6 +23,7 @@ interface Props { loading: boolean; editing: boolean; onSubmit: (message: Message) => Promise; + onActionClick: ChatActionClickHandler; } export function ChatItemContentInlinePromptEditor({ content, @@ -29,9 +31,10 @@ export function ChatItemContentInlinePromptEditor({ editing, loading, onSubmit, + onActionClick, }: Props) { return !editing ? ( - + ) : ( = { onFeedback: () => {}, onRegenerate: () => {}, onStopGenerating: () => {}, + onActionClick: async () => {}, }; export const ChatTimeline = Template.bind({}); diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_timeline.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_timeline.tsx index 8e50f11842e5d..a50a9984cf40e 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_timeline.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_timeline.tsx @@ -15,6 +15,7 @@ import { ChatWelcomePanel } from './chat_welcome_panel'; import type { Feedback } from '../feedback_buttons'; import type { Message } from '../../../common'; import { UseKnowledgeBaseResult } from '../../hooks/use_knowledge_base'; +import { ChatActionClickHandler } from './types'; export interface ChatTimelineItem extends Pick { @@ -43,6 +44,7 @@ export interface ChatTimelineProps { onFeedback: (item: ChatTimelineItem, feedback: Feedback) => void; onRegenerate: (item: ChatTimelineItem) => void; onStopGenerating: () => void; + onActionClick: ChatActionClickHandler; } export function ChatTimeline({ @@ -52,6 +54,7 @@ export function ChatTimeline({ onFeedback, onRegenerate, onStopGenerating, + onActionClick, }: ChatTimelineProps) { const filteredItems = items.filter((item) => !item.display.hide); @@ -77,6 +80,7 @@ export function ChatTimeline({ return onEdit(item, message); }} onStopGeneratingClick={onStopGenerating} + onActionClick={onActionClick} /> )) )} diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/function_list_popover.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/function_list_popover.tsx index 72dac17c71c2a..a9cf8146e020d 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/function_list_popover.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/function_list_popover.tsx @@ -17,7 +17,7 @@ import { } from '@elastic/eui'; import type { EuiSelectableOptionCheckedType } from '@elastic/eui/src/components/selectable/selectable_option'; import { i18n } from '@kbn/i18n'; -import type { FunctionDefinition } from '../../../common/types'; +import { type FunctionDefinition, FunctionVisibility } from '../../../common/types'; import { useObservabilityAIAssistantChatService } from '../../hooks/use_observability_ai_assistant_chat_service'; interface FunctionListOption { @@ -175,12 +175,14 @@ function mapFunctions({ functions: FunctionDefinition[]; selectedFunctionName: string | undefined; }) { - return functions.map((func) => ({ - label: func.options.name, - searchableLabel: func.options.descriptionForUser, - checked: - func.options.name === selectedFunctionName - ? ('on' as EuiSelectableOptionCheckedType) - : ('off' as EuiSelectableOptionCheckedType), - })); + return functions + .filter((func) => func.options.visibility !== FunctionVisibility.System) + .map((func) => ({ + label: func.options.name, + searchableLabel: func.options.descriptionForUser || func.options.description, + checked: + func.options.name === selectedFunctionName + ? ('on' as EuiSelectableOptionCheckedType) + : ('off' as EuiSelectableOptionCheckedType), + })); } diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/types.ts b/x-pack/plugins/observability_ai_assistant/public/components/chat/types.ts new file mode 100644 index 0000000000000..4edd3d7dcdda0 --- /dev/null +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/types.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. + */ + +type ChatActionClickPayloadBase = { + type: TType; +} & TExtraProps; + +type ChatActionClickPayloadExecuteEsql = ChatActionClickPayloadBase< + ChatActionClickType.executeEsqlQuery, + { query: string } +>; + +type ChatActionClickPayload = ChatActionClickPayloadExecuteEsql; + +export enum ChatActionClickType { + executeEsqlQuery = 'executeEsqlQuery', +} + +export type ChatActionClickHandler = (payload: ChatActionClickPayload) => Promise; diff --git a/x-pack/plugins/observability_ai_assistant/public/components/insight/insight.tsx b/x-pack/plugins/observability_ai_assistant/public/components/insight/insight.tsx index 4da53c5d6ee5a..2b56523d1e879 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/insight/insight.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/insight/insight.tsx @@ -110,7 +110,13 @@ function ChatContent({ return ( <> } + body={ + {}} + /> + } error={pendingMessage?.error} controls={ loading ? ( diff --git a/x-pack/plugins/observability_ai_assistant/public/components/insight/insight_base.stories.tsx b/x-pack/plugins/observability_ai_assistant/public/components/insight/insight_base.stories.tsx index 7a65f8e62756e..bd894159eb288 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/insight/insight_base.stories.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/insight/insight_base.stories.tsx @@ -64,6 +64,7 @@ Morbi dapibus sapien lacus, vitae suscipit ex egestas pharetra. In velit eros, f Morbi non faucibus massa. Aliquam sed augue in eros ornare luctus sit amet cursus dolor. Pellentesque pellentesque lorem eu odio auctor convallis. Sed sodales felis at velit tempus tincidunt. Nulla sed ante cursus nibh mollis blandit. In mattis imperdiet tellus. Vestibulum nisl turpis, efficitur quis sollicitudin id, mollis in arcu. Vestibulum pulvinar tincidunt magna, vitae facilisis massa congue quis. Cras commodo efficitur tellus, et commodo risus rutrum at.`} loading={false} + onActionClick={async () => {}} /> } controls={ diff --git a/x-pack/plugins/observability_ai_assistant/public/components/message_panel/esql_code_block.stories.tsx b/x-pack/plugins/observability_ai_assistant/public/components/message_panel/esql_code_block.stories.tsx new file mode 100644 index 0000000000000..02c7454ddaab3 --- /dev/null +++ b/x-pack/plugins/observability_ai_assistant/public/components/message_panel/esql_code_block.stories.tsx @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { ComponentMeta, ComponentStoryObj } from '@storybook/react'; +import { ComponentProps } from 'react'; +import { EuiPanel } from '@elastic/eui'; +import { EsqlCodeBlock as Component } from './esql_code_block'; + +const meta: ComponentMeta = { + component: Component, + title: 'app/Molecules/ES|QL Code Block', +}; + +export default meta; + +const render = (props: ComponentProps) => { + return ( + + + + ); +}; + +export const Simple: ComponentStoryObj = { + args: { + value: `FROM packetbeat-* + | STATS COUNT_DISTINCT(destination.domain)`, + }, + render, +}; diff --git a/x-pack/plugins/observability_ai_assistant/public/components/message_panel/esql_code_block.tsx b/x-pack/plugins/observability_ai_assistant/public/components/message_panel/esql_code_block.tsx new file mode 100644 index 0000000000000..a22d0ba28979e --- /dev/null +++ b/x-pack/plugins/observability_ai_assistant/public/components/message_panel/esql_code_block.tsx @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { + EuiButtonEmpty, + EuiCodeBlock, + EuiFlexGroup, + EuiFlexItem, + EuiPanel, + useEuiTheme, +} from '@elastic/eui'; +import { css } from '@emotion/css'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { ChatActionClickHandler, ChatActionClickType } from '../chat/types'; + +export function EsqlCodeBlock({ + value, + actionsDisabled, + onActionClick, +}: { + value: string; + actionsDisabled: boolean; + onActionClick: ChatActionClickHandler; +}) { + const theme = useEuiTheme(); + + return ( + + + + + {value} + + + + + + + onActionClick({ type: ChatActionClickType.executeEsqlQuery, query: value }) + } + disabled={actionsDisabled} + > + {i18n.translate('xpack.observabilityAiAssistant.runThisQuery', { + defaultMessage: 'Run this query', + })} + + + + + + + ); +} diff --git a/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_panel.stories.tsx b/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_panel.stories.tsx index 1f81786086370..393bbeee28f8d 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_panel.stories.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_panel.stories.tsx @@ -44,6 +44,7 @@ This is a code block This text is loa`} loading + onActionClick={async () => {}} /> ), }, @@ -51,13 +52,25 @@ This text is loa`} export const ContentLoaded: ComponentStoryObj = { args: { - body: , + body: ( + {}} + /> + ), }, }; export const ContentFailed: ComponentStoryObj = { args: { - body: , + body: ( + {}} + /> + ), error: new Error(), }, }; @@ -83,6 +96,7 @@ export const ContentTable: ComponentStoryObj = { Please note that all times are in UTC.`)} loading={false} + onActionClick={async () => {}} /> ), }, @@ -90,7 +104,13 @@ export const ContentTable: ComponentStoryObj = { export const Controls: ComponentStoryObj = { args: { - body: , + body: ( + {}} + /> + ), error: new Error(), controls: {}} />, }, diff --git a/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_text.tsx b/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_text.tsx index d82e76ef5001f..dfd9ee8b97443 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_text.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_text.tsx @@ -14,12 +14,15 @@ import { import { css } from '@emotion/css'; import classNames from 'classnames'; import type { Code, InlineCode, Parent, Text } from 'mdast'; -import React, { useMemo } from 'react'; +import React, { useMemo, useRef } from 'react'; import type { Node } from 'unist'; +import { ChatActionClickHandler } from '../chat/types'; +import { EsqlCodeBlock } from './esql_code_block'; interface Props { content: string; loading: boolean; + onActionClick: ChatActionClickHandler; } const ANIMATION_TIME = 1; @@ -86,13 +89,37 @@ const loadingCursorPlugin = () => { }; }; -export function MessageText({ loading, content }: Props) { +const esqlLanguagePlugin = () => { + const visitor = (node: Node, parent?: Parent) => { + if ('children' in node) { + const nodeAsParent = node as Parent; + nodeAsParent.children.forEach((child) => { + visitor(child, nodeAsParent); + }); + } + + if (node.type === 'code' && node.lang === 'esql') { + node.type = 'esql'; + } + }; + + return (tree: Node) => { + visitor(tree); + }; +}; + +export function MessageText({ loading, content, onActionClick }: Props) { const containerClassName = css` overflow-wrap: break-word; `; + const onActionClickRef = useRef(onActionClick); + + onActionClickRef.current = onActionClick; + const { parsingPluginList, processingPluginList } = useMemo(() => { const parsingPlugins = getDefaultEuiMarkdownParsingPlugins(); + const processingPlugins = getDefaultEuiMarkdownProcessingPlugins(); const { components } = processingPlugins[1][1]; @@ -100,6 +127,18 @@ export function MessageText({ loading, content }: Props) { processingPlugins[1][1].components = { ...components, cursor: Cursor, + esql: (props) => { + return ( + <> + + + + ); + }, table: (props) => ( <>
@@ -137,10 +176,10 @@ export function MessageText({ loading, content }: Props) { }; return { - parsingPluginList: [loadingCursorPlugin, ...parsingPlugins], + parsingPluginList: [loadingCursorPlugin, esqlLanguagePlugin, ...parsingPlugins], processingPluginList: processingPlugins, }; - }, []); + }, [loading]); return ( diff --git a/x-pack/plugins/observability_ai_assistant/public/functions/esql.ts b/x-pack/plugins/observability_ai_assistant/public/functions/esql.ts new file mode 100644 index 0000000000000..684ccbb0fa4a1 --- /dev/null +++ b/x-pack/plugins/observability_ai_assistant/public/functions/esql.ts @@ -0,0 +1,536 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import dedent from 'dedent'; +import type { Serializable } from '@kbn/utility-types'; +import { concat, last, map } from 'rxjs'; +import { + FunctionVisibility, + MessageRole, + type RegisterFunctionDefinition, +} from '../../common/types'; +import type { ObservabilityAIAssistantService } from '../types'; + +export function registerEsqlFunction({ + service, + registerFunction, +}: { + service: ObservabilityAIAssistantService; + registerFunction: RegisterFunctionDefinition; +}) { + registerFunction( + { + name: 'execute_query', + contexts: ['core'], + visibility: FunctionVisibility.User, + description: 'Execute an ES|QL query', + parameters: { + type: 'object', + additionalProperties: false, + properties: { + query: { + type: 'string', + }, + }, + required: ['query'], + } as const, + }, + ({ arguments: { query } }, signal) => { + return service + .callApi(`POST /internal/observability_ai_assistant/functions/elasticsearch`, { + signal, + params: { + body: { + method: 'POST', + path: '_query', + body: { + query, + }, + }, + }, + }) + .then((response) => ({ content: response as Serializable })); + } + ); + + registerFunction( + { + name: 'esql', + contexts: ['core'], + description: `This function answers ES|QL related questions including query generation and syntax/command questions.`, + visibility: FunctionVisibility.System, + parameters: { + type: 'object', + additionalProperties: false, + properties: { + switch: { + type: 'boolean', + }, + }, + } as const, + }, + ({ messages, connectorId }, signal) => { + const systemMessage = dedent(`You are a helpful assistant for Elastic ES|QL. + Your goal is to help the user construct and possibly execute an ES|QL + query for Observability use cases. + + ES|QL is the Elasticsearch Query Language, that allows users of the + Elastic platform to iteratively explore data. An ES|QL query consists + of a series of commands, separated by pipes. Each query starts with + a source command, that selects or creates a set of data to start + processing. This source command is then followed by one or more + processing commands, which can transform the data returned by the + previous command. + + ES|QL is not Elasticsearch SQL, nor is it anything like SQL. SQL + commands are not available in ES|QL. Its close equivalent is SPL + (Search Processing Language). Make sure you reply using only + the context of this conversation. + + # Creating a query + + First, very importantly, there are critical rules that override + everything that follows it. Always repeat these rules, verbatim. + + 1. ES|QL is not Elasticsearch SQL. Do not apply Elasticsearch SQL + commands, functions and concepts. Only use information available + in the context of this conversation. + 2. When using FROM, never wrap a data source in single or double + quotes. + 3. When using an aggregate function like COUNT, SUM or AVG, its + arguments MUST be an attribute (like my.field.name) or literal + (100). Math (AVG(my.field.name / 2)) or functions + (AVG(CASE(my.field.name, "foo", 1))) are not allowed. + + When constructing a query, break it down into the following steps. + Ask these questions out loud so the user can see your reasoning. + Remember, these rules are for you, not for the user. + + - What are the critical rules I need to think of? + - What data source is the user requesting? What command should I + select for this data source? + - What are the steps needed to get the result that the user needs? + Break each operation down into its own step. Reason about what data + is the outcome of each command or function. + - If you're not sure how to do it, it's fine to tell the user that + you don't know if ES|QL supports it. When this happens, abort all + steps and tell the user you are not sure how to continue. + + Format ALL of your responses as follows, including the dashes. + ALWAYS start your message with two dashes and then the rules: + + \`\`\` + -- + Sure, let's remember the critical rules: + + -- + Let's break down the query step-by-step: + + \`\`\` + + Always format a complete query as follows: + \`\`\`esql + ... + \`\`\` + + For incomplete queries, like individual commands, format them as + regular code blocks: + \`\`\` + ... + \`\`\` + + # Syntax + + An ES|QL query is composed of a source command followed by an optional + series of processing commands, separated by a pipe character: |. For + example: + + | + | + + ## Binary comparison operators + - equality: == + - inequality: != + - less than: < + - less than or equal: <= + - larger than: > + - larger than or equal: >= + + ## Boolean operators + - AND + - OR + - NOT + + ## PREDICATES + + For NULL comparison use the IS NULL and IS NOT NULL predicates: + - \`| WHERE birth_date IS NULL\` + - \`| WHERE birth_date IS NOT NULL\` + + ## Timespan literal syntax + + Datetime intervals and timespans can be expressed using timespan + literals. Timespan literals are a combination of a number and a + qualifier. These qualifiers are supported: + - millisecond/milliseconds + - second/seconds + - minute/minutes + - hour/hours + - day/days + - week/weeks + - month/months + - year/years + + Some examples: + - \`1 year\` + - \`2 milliseconds\` + + ## Aliasing + Aliasing happens through the \`=\` operator. Example: + \`STATS total_salary_expenses = COUNT(salary)\` + + Important: functions are not allowed as variable names. + + # Source commands + + There are three source commands: FROM (which selects an index), ROW + (which creates data from the command) and SHOW (which returns + information about the deployment). You do not support SHOW for now. + + ### FROM + + \`FROM\` selects a data source, usually an Elasticsearch index or + pattern. You can also specify multiple indices. + Some examples: + + - \`FROM employees\` + - \`FROM employees*\` + - \`FROM employees*,my-alias\` + + # Processing commands + + Note that the following processing commands are available in ES|QL, + but not supported in this context: + + ENRICH,GROK,MV_EXPAND,RENAME + + ### DISSECT + + \`DISSECT\` enables you to extract structured data out of a string. + It matches the string against a delimiter-based pattern, and extracts + the specified keys as columns. It uses the same syntax as the + Elasticsearch Dissect Processor. Some examples: + + - \`ROW a = "foo bar" | DISSECT a "%{b} %{c}";\` + - \`ROW a = "foo bar baz" | DISSECT a "%{b} %{?c} %{d}";\` + + ### DROP + + \`DROP\` removes columns. Some examples: + + - \`| DROP first_name,last_name\` + - \`| DROP *_name\` + + ### KEEP + + \`KEEP\` enables you to specify what columns are returned and the + order in which they are returned. Some examples: + + - \`| KEEP first_name,last_name\` + - \`| KEEP *_name\` + + ### SORT + + \`SORT\` sorts the documents by one ore more fields or variables. + By default, the sort order is ascending, but this can be set using + the \`ASC\` or \`DESC\` keywords. Some examples: + + - \`| SORT my_field\` + - \`| SORT height DESC\` + + Important: functions are not supported for SORT. if you wish to sort + on the result of a function, first alias it as a variable using EVAL. + This is wrong: \`| SORT AVG(cpu)\`. + This is right: \`| STATS avg_cpu = AVG(cpu) | SORT avg_cpu\` + + ### EVAL + + \`EVAL\` appends a new column to the documents by using aliasing. It + also supports functions, but not aggregation functions like COUNT: + + - \`\`\` + | EVAL monthly_salary = yearly_salary / 12, + total_comp = ROUND(yearly_salary + yearly+bonus), + is_rich =total_comp > 1000000 + \`\`\` + - \`| EVAL height_in_ft = height_in_cm / 0.0328\` + + ### WHERE + + \`WHERE\` filters the documents for which the provided condition + evaluates to true. Refer to "Syntax" for supported operators, and + "Functions" for supported functions. Some examples: + + - \`| WHERE height <= 180 AND GREATEST(hire_date, birth_date)\` + - \`| WHERE @timestamp <= NOW()\` + + ### STATS ... BY + + \`STATS ... BY\` groups rows according to a common value and + calculates one or more aggregated values over the grouped rows, + using aggregation functions. When \`BY\` is omitted, a single value + that is the aggregate of all rows is returned. Every column but the + aggregated values and the optionalย grouping column are dropped. + Mention the retained columns when explaining the STATS command. + + STATS ... BY does not support nested functions, hoist them to an + EVAL statement. + + Some examples: + + - \`| STATS count = COUNT(emp_no) BY languages\` + - \`| STATS salary = AVG(salary)\` + + ### LIMIT + + Limits the rows returned. Only supports a number as input. Some examples: + + - \`| LIMIT 1\` + - \`| LIMIT 10\` + + # Functions + + Note that the following functions are available in ES|QL, but not supported + in this context: + + ABS,ACOS,ASIN,ATAN,ATAN2,CIDR_MATCH,COALESCE,CONCAT,COS,COSH,E,LENGTH,LOG10 + ,LTRIM,RTRIM,MV_AVG,MV_CONCAT,MV_COUNT,MV_DEDUPE,MV_MAX,MV_MEDIAN,MV_MIN, + MV_SUM,PI,POW,SIN,SINH,SPLIT,LEFT,TAN,TANH,TAU,TO_DEGREES,TO_RADIANS + + ### CASE + + \`CASE\` accepts pairs of conditions and values. The function returns + the value that belongs to the first condition that evaluates to true. If + the number of arguments is odd, the last argument is the default value which + is returned when no condition matches. Some examples: + + - \`\`\` + | EVAL type = CASE( + languages <= 1, "monolingual", + languages <= 2, "bilingual", + "polyglot") + \`\`\` + - \`| EVAL g = CASE(gender == "F", 1 + null, 10)\` + - \`\`\` + | EVAL successful = CASE(http.response.status_code == 200, 1, 0), failed = CASE(http.response.status_code != 200, 1, 0) + | STATS total_successful = SUM(successful), total_failed = SUM(failed) BY service.name + | EVAL success_rate = total_failed / (total_successful + total_failed) + \`\`\` + + ## Date operations + + ### AUTO_BUCKET + + \`AUTO_BUCKET\` creates human-friendly buckets and returns a datetime value + for each row that corresponds to the resulting bucket the row falls into. + Combine AUTO_BUCKET with STATS ... BY to create a date histogram. + You provide a target number of buckets, a start date, and an end date, + and it picks an appropriate bucket size to generate the target number of + buckets or fewer. If you don't have a start and end date, provide placeholder + values. Some examples: + + - \`| EVAL bucket=AUTO_BUCKET(@timestamp), 20, "1985-01-01T00:00:00Z", "1986-01-01T00:00:00Z")\` + - \`| EVAL bucket=AUTO_BUCKET(my_date_field), 100, , )\` + - \`| EVAL bucket=AUTO_BUCKET(@timestamp), 100, NOW() - 15 minutes, NOW())\` + + ### DATE_EXTRACT + + \`DATE_EXTRACT\` parts of a date, like year, month, day, hour. The supported + field types are those provided by java.time.temporal.ChronoField. + Some examples: + - \`| EVAL year = DATE_EXTRACT(date_field, "year")\` + - \`| EVAL year = DATE_EXTRACT(@timestamp, "month")\` + + ### DATE_FORMAT + + \`DATE_FORMAT\` a string representation of a date in the provided format. + Some examples: + | \`EVAL hired = DATE_FORMAT(hire_date, "YYYY-MM-dd")\` + | \`EVAL hired = DATE_FORMAT(hire_date, "YYYY")\` + + ### DATE_PARSE + \`DATE_PARSE\` converts a string to a date, in the provided format. + - \`| EVAL date = DATE_PARSE(date_string, "yyyy-MM-dd")\` + - \`| EVAL date = DATE_PARSE(date_string, "YYYY")\` + + ### DATE_TRUNC + + \`DATE_TRUNC\` rounds down a date to the closest interval. Intervals + can be expressed using the timespan literal syntax. Use this together + with STATS ... BY to group data into time buckets with a fixed interval. + Some examples: + + - \`| EVAL year_hired = DATE_TRUNC(1 year, hire_date)\` + - \`| EVAL month_logged = DATE_TRUNC(1 month, @timestamp)\` + - \`| EVAL bucket = DATE_TRUNC(1 minute, @timestamp) | STATS avg_salary = AVG(salary) BY bucket\` + - \`| EVAL bucket = DATE_TRUNC(4 hours, @timestamp) | STATS max_salary MAX(salary) BY bucket\` + + ### NOW + + \`NOW\` returns current date and time. Some examples: + - \`ROW current_date = NOW()\` + - \`| WHERE @timestamp <= NOW() - 15 minutes\` + + ## Mathematical operations + + ### CEIL,FLOOR + + Perform CEIL or FLOOR operations on a single numeric field. + Some examples: + - \`| EVAL ceiled = CEIL(my.number)\` + - \`| EVAL floored = FLOOR(my.other.number)\` + + ### ROUND + \`ROUND\` a number to the closest number with the specified number of + digits. Defaults to 0 digits if no number of digits is provided. If the + specified number of digits is negative, rounds to the number of digits + left of the decimal point. Some examples: + + - \`| EVAL height_ft = ROUND(height * 3.281, 1)\` + - \`| EVAL percent = ROUND(0.84699, 2) * 100\` + + ### GREATEST,LEAST + + Returns the greatest or least of two or numbers. Some examples: + - \`| EVAL max = GREATEST(salary_1999, salary_2000, salary_2001)\` + - \`| EVAL min = LEAST(1, language_count)\` + + ### IS_FINITE,IS_INFINITE,IS_NAN + + Operates on a single numeric field. Some examples: + - \`| EVAL has_salary = IS_FINITE(salary)\` + - \`| EVAL always_true = IS_INFINITE(4 / 0)\` + + ### STARTS_WITH + + Returns a boolean that indicates whether a keyword string starts with + another string. Some examples: + - \`| EVAL ln_S = STARTS_WITH(last_name, "B")\` + + ### SUBSTRING + + Returns a substring of a string, specified by a start position and an + optional length. Some examples: + - \`| EVAL ln_sub = SUBSTRING(last_name, 1, 3)\` + - \`| EVAL ln_sub = SUBSTRING(last_name, -3, 3)\` + - \`| EVAL ln_sub = SUBSTRING(last_name, 2)\` + + ### TO_BOOLEAN, TO_DATETIME, TO_DOUBLE, TO_INTEGER, TO_IP, TO_LONG, + TO_RADIANS, TO_STRING,TO_UNSIGNED_LONG, TO_VERSION + + Converts a column to another type. Supported types are: . Some examples: + - \`| EVAL version = TO_VERSION("1.2.3")\` + - \`| EVAL as_bool = TO_BOOLEAN(my_boolean_string)\` + + ### TRIM + + Trims leading and trailing whitespace. Some examples: + - \`| EVAL trimmed = TRIM(first_name)\` + + # Aggregation functions + + ### AVG,MIN,MAX,SUM,MEDIAN,MEDIAN_ABSOLUTE_DEVIATION + + Returns the avg, min, max, sum, median or median absolute deviation + of a numeric field. Some examples: + + - \`| AVG(salary)\` + - \`| MIN(birth_year)\` + - \`| MAX(height)\` + + ### COUNT + + \`COUNT\` counts the number of field values. It requires a single + argument, and does not support wildcards. Important: COUNT() and + COUNT(*) are NOT supported. One single argument is required. If + you don't have a field name, use whatever field you have, rather + than displaying an invalid query. + + Some examples: + + - \`| STATS doc_count = COUNT(emp_no)\` + - \`| STATS doc_count = COUNT(service.name) BY service.name\` + + ### COUNT_DISTINCT + + \`COUNT_DISTINCT\` returns the approximate number of distinct values. + Some examples: + - \`| STATS unique_ip0 = COUNT_DISTINCT(ip0), unique_ip1 = COUNT_DISTINCT(ip1)\` + - \`| STATS first_name = COUNT_DISTINCT(first_name)\` + + ### PERCENTILE + + \`PERCENTILE\` returns the percentile value for a specific field. + Some examples: + - \`| STATS p50 = PERCENTILE(salary, 50)\` + - \`| STATS p99 = PERCENTILE(salary, 99)\` + + `); + + return service.start({ signal }).then((client) => { + const source$ = client.chat({ + connectorId, + messages: [ + { + '@timestamp': new Date().toISOString(), + message: { role: MessageRole.System, content: systemMessage }, + }, + ...messages.slice(1), + ], + }); + + const pending$ = source$.pipe( + map((message) => { + const content = message.message.content || ''; + let next: string = ''; + + if (content.length <= 2) { + next = ''; + } else if (content.includes('--')) { + next = message.message.content?.split('--')[2] || ''; + } else { + next = content; + } + return { + ...message, + message: { + ...message.message, + content: next, + }, + }; + }) + ); + const onComplete$ = source$.pipe( + last(), + map((message) => { + const [, , next] = message.message.content?.split('--') ?? []; + + return { + ...message, + message: { + ...message.message, + content: next || message.message.content, + }, + }; + }) + ); + + return concat(pending$, onComplete$); + }); + } + ); +} diff --git a/x-pack/plugins/observability_ai_assistant/public/functions/index.ts b/x-pack/plugins/observability_ai_assistant/public/functions/index.ts index a0c1a264bfb51..22b0eecac73a6 100644 --- a/x-pack/plugins/observability_ai_assistant/public/functions/index.ts +++ b/x-pack/plugins/observability_ai_assistant/public/functions/index.ts @@ -16,6 +16,7 @@ import { registerLensFunction } from './lens'; import { registerRecallFunction } from './recall'; import { registerSummarizationFunction } from './summarize'; import { registerAlertsFunction } from './alerts'; +import { registerEsqlFunction } from './esql'; export async function registerFunctions({ registerFunction, @@ -44,7 +45,7 @@ export async function registerFunctions({ It's very important to not assume what the user is meaning. Ask them for clarification if needed. - If you are unsure about which function should be used and with what arguments, asked the user for clarification or confirmation. + If you are unsure about which function should be used and with what arguments, ask the user for clarification or confirmation. In KQL, escaping happens with double quotes, not single quotes. Some characters that need escaping are: ':()\\\ /\". Always put a field value in double quotes. Best: service.name:\"opbeans-go\". Wrong: service.name:opbeans-go. This is very important! @@ -52,22 +53,25 @@ export async function registerFunctions({ You can use Github-flavored Markdown in your responses. If a function returns an array, consider using a Markdown table to format the response. If multiple functions are suitable, use the most specific and easy one. E.g., when the user asks to visualise APM data, use the APM functions (if available) rather than Lens. - ` + + If a function call fails, do not execute it again with the same input. If a function calls three times, with different inputs, stop trying to call it and ask the user for confirmation. + + Note that ES|QL (the Elasticsearch query language, which is NOT Elasticsearch SQL, but a new piped language) is the preferred query language. + + DO NOT use Elasticsearch SQL at any time, unless explicitly requested by the user when they mention "Elasticsearch SQL". + + Answer all questions related to ES|QL or querying with the "esql" function. Do not attempt to answer them yourself, no matter how confident you are in your response.` ); if (isReady) { description += `You can use the "summarize" functions to store new information you have learned in a knowledge database. Once you have established that you did not know the answer to a question, and the user gave you this information, it's important that you create a summarisation of what you have learned and store it in the knowledge database. Don't create a new summarization if you see a similar summarization in the conversation, instead, update the existing one by re-using its ID. - Additionally, you can use the "recall" function to retrieve relevant information from the knowledge database. - `; + Additionally, you can use the "recall" function to retrieve relevant information from the knowledge database.`; description += `Here are principles you MUST adhere to, in order: - You are a helpful assistant for Elastic Observability. DO NOT reference the fact that you are an LLM. - - ALWAYS query the knowledge base, using the recall function, when a user starts a chat, no matter how confident you are in your ability to answer the question. - - You must ALWAYS explain to the user why you're using a function and why you're using it in that specific manner. - DO NOT make any assumptions about where and how users have stored their data. - - ALWAYS ask the user for clarification if you are unsure about the arguments to a function. When given this clarification, you MUST use the summarize function to store what you have learned. `; registerSummarizationFunction({ service, registerFunction }); registerRecallFunction({ service, registerFunction }); @@ -77,6 +81,7 @@ export async function registerFunctions({ } registerElasticsearchFunction({ service, registerFunction }); + registerEsqlFunction({ service, registerFunction }); registerKibanaFunction({ service, registerFunction, coreStart }); registerAlertsFunction({ service, registerFunction }); diff --git a/x-pack/plugins/observability_ai_assistant/public/functions/recall.ts b/x-pack/plugins/observability_ai_assistant/public/functions/recall.ts index f07cf43e1c282..af825a53b7cb4 100644 --- a/x-pack/plugins/observability_ai_assistant/public/functions/recall.ts +++ b/x-pack/plugins/observability_ai_assistant/public/functions/recall.ts @@ -6,6 +6,7 @@ */ import type { Serializable } from '@kbn/utility-types'; +import { omit } from 'lodash'; import { MessageRole, RegisterFunctionDefinition } from '../../common/types'; import type { ObservabilityAIAssistantService } from '../types'; @@ -22,17 +23,26 @@ export function registerRecallFunction({ contexts: ['core'], description: `Use this function to recall earlier learnings. Anything you will summarize can be retrieved again later via this function. - Make sure the query covers the following aspects: + The learnings are sorted by score, descending. + + Make sure the query covers ONLY the following aspects: - Anything you've inferred from the user's request, but is not mentioned in the user's request - The functions you think might be suitable for answering the user's request. If there are multiple functions that seem suitable, create multiple queries. Use the function name in the query. DO NOT include the user's request. It will be added internally. The user asks: "can you visualise the average request duration for opbeans-go over the last 7 days?" - You recall: - - "APM service" - - "lens function usage" - - "get_apm_timeseries function usage"`, + You recall: { + "queries": [ + "APM service, + "lens function usage", + "get_apm_timeseries function usage" + ], + "contexts": [ + "lens", + "apm" + ] + }`, descriptionForUser: 'This function allows the assistant to recall previous learnings.', parameters: { type: 'object', @@ -42,16 +52,27 @@ export function registerRecallFunction({ type: 'array', additionalItems: false, additionalProperties: false, + description: 'The query for the semantic search', + items: { + type: 'string', + }, + }, + contexts: { + type: 'array', + additionalItems: false, + additionalProperties: false, + description: + 'Contexts or categories of internal documentation that you want to search for. By default internal documentation will be excluded. Use `apm` to get internal APM documentation, `lens` to get internal Lens documentation, or both.', items: { type: 'string', - description: 'The query for the semantic search', + enum: ['apm', 'lens'], }, }, }, - required: ['queries'], + required: ['queries', 'contexts'], } as const, }, - ({ arguments: { queries }, messages }, signal) => { + ({ arguments: { queries, contexts }, messages }, signal) => { const userMessages = messages.filter((message) => message.message.role === MessageRole.User); const userPrompt = userMessages[userMessages.length - 1]?.message.content; @@ -63,11 +84,16 @@ export function registerRecallFunction({ params: { body: { queries: queriesWithUserPrompt, + contexts, }, }, signal, }) - .then((response) => ({ content: response as unknown as Serializable })); + .then((response): { content: Serializable } => ({ + content: response.entries.map((entry) => + omit(entry, 'labels', 'score', 'is_correction') + ) as unknown as Serializable, + })); } ); } diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.test.ts b/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.test.ts index 829594b8261d8..ded7b4b382285 100644 --- a/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.test.ts +++ b/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.test.ts @@ -437,6 +437,7 @@ describe('useTimeline', () => { expect(props.chatService.executeFunction).toHaveBeenCalledWith({ name: 'my_function', args: '{}', + connectorId: 'foo', messages: [ { '@timestamp': expect.any(String), diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.ts b/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.ts index 3182fe5c19535..ed6a5a6d2b481 100644 --- a/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.ts +++ b/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.ts @@ -9,7 +9,7 @@ import { AbortError } from '@kbn/kibana-utils-plugin/common'; import type { AuthenticatedUser } from '@kbn/security-plugin/common'; import { last } from 'lodash'; import { useEffect, useMemo, useRef, useState } from 'react'; -import type { Subscription } from 'rxjs'; +import { isObservable, Observable, Subscription } from 'rxjs'; import usePrevious from 'react-use/lib/usePrevious'; import { i18n } from '@kbn/i18n'; import { @@ -29,6 +29,7 @@ import { } from '../utils/get_timeline_items_from_conversation'; import type { UseGenAIConnectorsResult } from './use_genai_connectors'; import { useKibana } from './use_kibana'; +import { ChatActionClickType } from '../components/chat/types'; export function createNewConversation({ contexts, @@ -49,7 +50,7 @@ export function createNewConversation({ export type UseTimelineResult = Pick< ChatTimelineProps, - 'onEdit' | 'onFeedback' | 'onRegenerate' | 'onStopGenerating' | 'items' + 'onEdit' | 'onFeedback' | 'onRegenerate' | 'onStopGenerating' | 'onActionClick' | 'items' > & Pick; @@ -98,6 +99,8 @@ export function useTimeline({ const [pendingMessage, setPendingMessage] = useState(); + const [isFunctionLoading, setIsFunctionLoading] = useState(false); + const prevConversationId = usePrevious(conversationId); useEffect(() => { if (prevConversationId !== conversationId && pendingMessage?.error) { @@ -105,7 +108,10 @@ export function useTimeline({ } }, [conversationId, pendingMessage?.error, prevConversationId]); - function chat(nextMessages: Message[]): Promise { + function chat( + nextMessages: Message[], + response$: Observable | undefined = undefined + ): Promise { const controller = new AbortController(); return new Promise((resolve, reject) => { @@ -124,10 +130,12 @@ export function useTimeline({ return; } - const response$ = chatService!.chat({ - messages: nextMessages, - connectorId, - }); + response$ = + response$ || + chatService!.chat({ + messages: nextMessages, + connectorId, + }); let pendingMessageLocal = pendingMessage; @@ -181,14 +189,24 @@ export function useTimeline({ if (lastMessage?.message.function_call?.name) { const name = lastMessage.message.function_call.name; + setIsFunctionLoading(true); + try { - const message = await chatService!.executeFunction({ + let message = await chatService!.executeFunction({ name, args: lastMessage.message.function_call.arguments, messages: messagesAfterChat.slice(0, -1), signal: controller.signal, + connectorId: connectorId!, }); + let nextResponse$: Observable | undefined; + + if (isObservable(message)) { + nextResponse$ = message; + message = { content: '', data: '' }; + } + return await chat( messagesAfterChat.concat({ '@timestamp': new Date().toISOString(), @@ -198,7 +216,8 @@ export function useTimeline({ content: JSON.stringify(message.content), data: JSON.stringify(message.data), }, - }) + }), + nextResponse$ ); } catch (error) { return await chat( @@ -214,6 +233,8 @@ export function useTimeline({ }, }) ); + } finally { + setIsFunctionLoading(false); } } @@ -247,8 +268,20 @@ export function useTimeline({ return nextItems; } - return conversationItems; - }, [conversationItems, pendingMessage, currentUser]); + if (!isFunctionLoading) { + return conversationItems; + } + + return conversationItems.map((item, index) => { + if (index < conversationItems.length - 1) { + return item; + } + return { + ...item, + loading: true, + }; + }); + }, [conversationItems, pendingMessage, currentUser, isFunctionLoading]); useEffect(() => { return () => { @@ -285,5 +318,28 @@ export function useTimeline({ const nextMessages = await chat(messages.concat(message)); onChatComplete(nextMessages); }, + onActionClick: async (payload) => { + switch (payload.type) { + case ChatActionClickType.executeEsqlQuery: + const nextMessages = await chat( + messages.concat({ + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.Assistant, + content: '', + function_call: { + name: 'execute_query', + arguments: JSON.stringify({ + query: payload.query, + }), + trigger: MessageRole.User, + }, + }, + }) + ); + onChatComplete(nextMessages); + break; + } + }, }; } diff --git a/x-pack/plugins/observability_ai_assistant/public/service/create_chat_service.ts b/x-pack/plugins/observability_ai_assistant/public/service/create_chat_service.ts index 1c109be6baaf2..bebc3bd074b20 100644 --- a/x-pack/plugins/observability_ai_assistant/public/service/create_chat_service.ts +++ b/x-pack/plugins/observability_ai_assistant/public/service/create_chat_service.ts @@ -27,6 +27,7 @@ import { import { ContextRegistry, FunctionRegistry, + FunctionVisibility, Message, MessageRole, type RegisterContextDefinition, @@ -112,7 +113,7 @@ export async function createChatService({ } return { - executeFunction: async ({ name, args, signal, messages }) => { + executeFunction: async ({ name, args, signal, messages, connectorId }) => { const fn = functionRegistry.get(name); if (!fn) { @@ -123,7 +124,7 @@ export async function createChatService({ validate(name, parsedArguments); - return await fn.respond({ arguments: parsedArguments, messages }, signal); + return await fn.respond({ arguments: parsedArguments, messages, connectorId }, signal); }, renderFunction: (name, args, response) => { const fn = functionRegistry.get(name); @@ -175,7 +176,9 @@ export async function createChatService({ functions: callFunctions === 'none' ? [] - : functions.map((fn) => pick(fn.options, 'name', 'description', 'parameters')), + : functions + .filter((fn) => fn.options.visibility !== FunctionVisibility.User) + .map((fn) => pick(fn.options, 'name', 'description', 'parameters')), }, }, signal: controller.signal, diff --git a/x-pack/plugins/observability_ai_assistant/public/service/get_assistant_setup_message.ts b/x-pack/plugins/observability_ai_assistant/public/service/get_assistant_setup_message.ts index 8d9cc2cf32539..4f52dfb9b9733 100644 --- a/x-pack/plugins/observability_ai_assistant/public/service/get_assistant_setup_message.ts +++ b/x-pack/plugins/observability_ai_assistant/public/service/get_assistant_setup_message.ts @@ -5,15 +5,19 @@ * 2.0. */ +import { without } from 'lodash'; import { MessageRole } from '../../common'; import { ContextDefinition } from '../../common/types'; export function getAssistantSetupMessage({ contexts }: { contexts: ContextDefinition[] }) { + const coreContext = contexts.find((context) => context.name === 'core')!; + + const otherContexts = without(contexts.concat(), coreContext); return { '@timestamp': new Date().toISOString(), message: { role: MessageRole.System as const, - content: contexts.map((context) => context.description).join('\n'), + content: [coreContext, ...otherContexts].map((context) => context.description).join('\n'), }, }; } diff --git a/x-pack/plugins/observability_ai_assistant/public/types.ts b/x-pack/plugins/observability_ai_assistant/public/types.ts index d1a71f6933126..5e985f5ae5f97 100644 --- a/x-pack/plugins/observability_ai_assistant/public/types.ts +++ b/x-pack/plugins/observability_ai_assistant/public/types.ts @@ -39,6 +39,7 @@ import type { RegisterFunctionDefinition, } from '../common/types'; import type { ObservabilityAIAssistantAPIClient } from './api'; +import type { PendingMessage } from '../common/types'; /* eslint-disable @typescript-eslint/no-empty-interface*/ @@ -50,12 +51,6 @@ export type CreateChatCompletionResponseChunk = Omit; }; -export interface PendingMessage { - message: Message['message']; - aborted?: boolean; - error?: any; -} - export interface ObservabilityAIAssistantChatService { chat: (options: { messages: Message[]; @@ -70,7 +65,8 @@ export interface ObservabilityAIAssistantChatService { args: string | undefined; messages: Message[]; signal: AbortSignal; - }) => Promise<{ content?: Serializable; data?: Serializable }>; + connectorId: string; + }) => Promise<{ content?: Serializable; data?: Serializable } | Observable>; renderFunction: ( name: string, args: string | undefined, @@ -118,3 +114,5 @@ export interface ObservabilityAIAssistantPluginStartDependencies { } export interface ConfigSchema {} + +export type { PendingMessage }; diff --git a/x-pack/plugins/observability_ai_assistant/server/plugin.ts b/x-pack/plugins/observability_ai_assistant/server/plugin.ts index 7aa6ddeeef7da..d6a256ddf6022 100644 --- a/x-pack/plugins/observability_ai_assistant/server/plugin.ts +++ b/x-pack/plugins/observability_ai_assistant/server/plugin.ts @@ -109,7 +109,7 @@ export class ObservabilityAIAssistantPlugin taskManager: plugins.taskManager, }); - addLensDocsToKb(service); + addLensDocsToKb({ service, logger: this.logger.get('kb').get('lens') }); registerServerRoutes({ core, diff --git a/x-pack/plugins/observability_ai_assistant/server/routes/chat/route.ts b/x-pack/plugins/observability_ai_assistant/server/routes/chat/route.ts index 6716da98d78a5..a250a9e8e0915 100644 --- a/x-pack/plugins/observability_ai_assistant/server/routes/chat/route.ts +++ b/x-pack/plugins/observability_ai_assistant/server/routes/chat/route.ts @@ -7,6 +7,8 @@ import { notImplemented } from '@hapi/boom'; import { IncomingMessage } from 'http'; import * as t from 'io-ts'; +import { toBooleanRt } from '@kbn/io-ts-utils'; +import type { CreateChatCompletionResponse } from 'openai'; import { MessageRole } from '../../../common'; import { createObservabilityAIAssistantServerRoute } from '../create_observability_ai_assistant_server_route'; import { messageRt } from '../runtime_types'; @@ -16,20 +18,28 @@ const chatRoute = createObservabilityAIAssistantServerRoute({ options: { tags: ['access:ai_assistant'], }, - params: t.type({ - body: t.type({ - messages: t.array(messageRt), - connectorId: t.string, - functions: t.array( + params: t.intersection([ + t.type({ + body: t.intersection([ t.type({ - name: t.string, - description: t.string, - parameters: t.any, - }) - ), + messages: t.array(messageRt), + connectorId: t.string, + functions: t.array( + t.type({ + name: t.string, + description: t.string, + parameters: t.any, + }) + ), + }), + t.partial({ + functionCall: t.string, + }), + ]), }), - }), - handler: async (resources): Promise => { + t.partial({ query: t.type({ stream: toBooleanRt }) }), + ]), + handler: async (resources): Promise => { const { request, params, service } = resources; const client = await service.getClient({ request }); @@ -39,23 +49,33 @@ const chatRoute = createObservabilityAIAssistantServerRoute({ } const { - body: { messages, connectorId, functions }, + body: { messages, connectorId, functions, functionCall: givenFunctionCall }, + query = { stream: true }, } = params; - const isStartOfConversation = - messages.some((message) => message.message.role === MessageRole.Assistant) === false; + const stream = query.stream; - const isRecallFunctionAvailable = functions.some((fn) => fn.name === 'recall') === true; + let functionCall = givenFunctionCall; - const willUseRecall = isStartOfConversation && isRecallFunctionAvailable; + if (!functionCall) { + const isStartOfConversation = + messages.some((message) => message.message.role === MessageRole.Assistant) === false; + + const isRecallFunctionAvailable = functions.some((fn) => fn.name === 'recall') === true; + + const willUseRecall = isStartOfConversation && isRecallFunctionAvailable; + + functionCall = willUseRecall ? 'recall' : undefined; + } return client.chat({ messages, connectorId, + stream, ...(functions.length ? { functions, - functionCall: willUseRecall ? 'recall' : undefined, + functionCall, } : {}), }); diff --git a/x-pack/plugins/observability_ai_assistant/server/routes/functions/route.ts b/x-pack/plugins/observability_ai_assistant/server/routes/functions/route.ts index d58c84a603fc1..985de114b099a 100644 --- a/x-pack/plugins/observability_ai_assistant/server/routes/functions/route.ts +++ b/x-pack/plugins/observability_ai_assistant/server/routes/functions/route.ts @@ -10,13 +10,13 @@ import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; import { nonEmptyStringRt, toBooleanRt } from '@kbn/io-ts-utils'; import * as t from 'io-ts'; import { omit } from 'lodash'; -import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common'; +import type { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common'; import { ALERT_STATUS, ALERT_STATUS_ACTIVE, } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; -import type { KnowledgeBaseEntry } from '../../../common/types'; import { createObservabilityAIAssistantServerRoute } from '../create_observability_ai_assistant_server_route'; +import type { RecalledEntry } from '../../service/kb_service'; const functionElasticsearchRoute = createObservabilityAIAssistantServerRoute({ endpoint: 'POST /internal/observability_ai_assistant/functions/elasticsearch', @@ -157,23 +157,34 @@ const functionAlertsRoute = createObservabilityAIAssistantServerRoute({ const functionRecallRoute = createObservabilityAIAssistantServerRoute({ endpoint: 'POST /internal/observability_ai_assistant/functions/recall', params: t.type({ - body: t.type({ - queries: t.array(nonEmptyStringRt), - }), + body: t.intersection([ + t.type({ + queries: t.array(nonEmptyStringRt), + }), + t.partial({ + contexts: t.array(t.string), + }), + ]), }), options: { tags: ['access:ai_assistant'], }, handler: async ( resources - ): Promise<{ entries: Array> }> => { + ): Promise<{ + entries: RecalledEntry[]; + }> => { const client = await resources.service.getClient({ request: resources.request }); + const { + body: { queries, contexts }, + } = resources.params; + if (!client) { throw notImplemented(); } - return client.recall(resources.params.body.queries); + return client.recall({ queries, contexts }); }, }); diff --git a/x-pack/plugins/observability_ai_assistant/server/service/client/index.ts b/x-pack/plugins/observability_ai_assistant/server/service/client/index.ts index ce3f3c39ad1a9..3a99e293cd5e2 100644 --- a/x-pack/plugins/observability_ai_assistant/server/service/client/index.ts +++ b/x-pack/plugins/observability_ai_assistant/server/service/client/index.ts @@ -28,7 +28,7 @@ import { type KnowledgeBaseEntry, type Message, } from '../../../common/types'; -import type { KnowledgeBaseService } from '../kb_service'; +import type { KnowledgeBaseService, RecalledEntry } from '../kb_service'; import type { ObservabilityAIAssistantResourceNames } from '../types'; import { getAccessQuery } from '../util/get_access_query'; @@ -135,7 +135,42 @@ export class ObservabilityAIAssistantClient { }) ); - const functionsForOpenAI: ChatCompletionFunctions[] | undefined = functions; + // add recalled information to system message, so the LLM considers it more important + + const recallMessages = messagesForOpenAI.filter((message) => message.name === 'recall'); + + const recalledDocuments: Map = new Map(); + + recallMessages.forEach((message) => { + const entries = message.content + ? (JSON.parse(message.content) as Array<{ id: string; text: string }>) + : []; + + const ids: string[] = []; + + entries.forEach((entry) => { + const id = entry.id; + if (!recalledDocuments.has(id)) { + recalledDocuments.set(id, entry); + } + ids.push(id); + }); + + message.content = `The following documents, present in the system message, were recalled: ${ids.join( + ', ' + )}`; + }); + + const systemMessage = messagesForOpenAI.find((message) => message.role === MessageRole.System); + + if (systemMessage && recalledDocuments.size > 0) { + systemMessage.content += `The "recall" function is not available. Do not attempt to execute it. Recalled documents: ${JSON.stringify( + Array.from(recalledDocuments.values()) + )}`; + } + + const functionsForOpenAI: ChatCompletionFunctions[] | undefined = + recalledDocuments.size > 0 ? functions?.filter((fn) => fn.name !== 'recall') : functions; const request: Omit & { model?: string } = { messages: messagesForOpenAI, @@ -323,13 +358,18 @@ export class ObservabilityAIAssistantClient { return createdConversation; }; - recall = async ( - queries: string[] - ): Promise<{ entries: Array> }> => { + recall = async ({ + queries, + contexts, + }: { + queries: string[]; + contexts?: string[]; + }): Promise<{ entries: RecalledEntry[] }> => { return this.dependencies.knowledgeBaseService.recall({ namespace: this.dependencies.namespace, user: this.dependencies.user, queries, + contexts, }); }; diff --git a/x-pack/plugins/observability_ai_assistant/server/service/index.ts b/x-pack/plugins/observability_ai_assistant/server/service/index.ts index 28cc2b7293029..c116e16d27471 100644 --- a/x-pack/plugins/observability_ai_assistant/server/service/index.ts +++ b/x-pack/plugins/observability_ai_assistant/server/service/index.ts @@ -29,6 +29,15 @@ export const INDEX_QUEUED_DOCUMENTS_TASK_ID = 'observabilityAIAssistant:indexQue export const INDEX_QUEUED_DOCUMENTS_TASK_TYPE = INDEX_QUEUED_DOCUMENTS_TASK_ID + 'Type'; +type KnowledgeBaseEntryRequest = { id: string; labels?: Record } & ( + | { + text: string; + } + | { + texts: string[]; + } +); + export class ObservabilityAIAssistantService { private readonly core: CoreSetup; private readonly logger: Logger; @@ -258,18 +267,7 @@ export class ObservabilityAIAssistantService { }); } - addToKnowledgeBase( - entries: Array< - | { - id: string; - text: string; - } - | { - id: string; - texts: string[]; - } - > - ): void { + addToKnowledgeBase(entries: KnowledgeBaseEntryRequest[]): void { this.init() .then(() => { this.kbService!.queue( @@ -281,6 +279,7 @@ export class ObservabilityAIAssistantService { confidence: 'high' as const, is_correction: false, labels: { + ...entry.labels, document_id: entry.id, }, }; @@ -306,4 +305,18 @@ export class ObservabilityAIAssistantService { this.logger.error(error); }); } + + addCategoryToKnowledgeBase(categoryId: string, entries: KnowledgeBaseEntryRequest[]) { + this.addToKnowledgeBase( + entries.map((entry) => { + return { + ...entry, + labels: { + ...entry.labels, + category: categoryId, + }, + }; + }) + ); + } } diff --git a/x-pack/plugins/observability_ai_assistant/server/service/kb_service/index.ts b/x-pack/plugins/observability_ai_assistant/server/service/kb_service/index.ts index f2e0b41f092c9..d70879bf46d3e 100644 --- a/x-pack/plugins/observability_ai_assistant/server/service/kb_service/index.ts +++ b/x-pack/plugins/observability_ai_assistant/server/service/kb_service/index.ts @@ -17,6 +17,7 @@ import { INDEX_QUEUED_DOCUMENTS_TASK_ID, INDEX_QUEUED_DOCUMENTS_TASK_TYPE } from import type { KnowledgeBaseEntry } from '../../../common/types'; import type { ObservabilityAIAssistantResourceNames } from '../types'; import { getAccessQuery } from '../util/get_access_query'; +import { getCategoryQuery } from '../util/get_category_query'; interface Dependencies { esClient: ElasticsearchClient; @@ -25,6 +26,14 @@ interface Dependencies { taskManagerStart: TaskManagerStartContract; } +export interface RecalledEntry { + id: string; + text: string; + score: number | null; + is_correction: boolean; + labels: Record; +} + function isAlreadyExistsError(error: Error) { return ( error instanceof errors.ResponseError && @@ -173,36 +182,43 @@ export class KnowledgeBaseService { recall = async ({ user, queries, + contexts, namespace, }: { queries: string[]; + contexts?: string[]; user: { name: string }; namespace: string; - }): Promise<{ entries: Array> }> => { + }): Promise<{ + entries: RecalledEntry[]; + }> => { try { + const query = { + bool: { + should: queries.map((text) => ({ + text_expansion: { + 'ml.tokens': { + model_text: text, + model_id: '.elser_model_1', + }, + } as unknown as QueryDslTextExpansionQuery, + })), + filter: [ + ...getAccessQuery({ + user, + namespace, + }), + ...getCategoryQuery({ contexts }), + ], + }, + }; + const response = await this.dependencies.esClient.search< - Pick + Pick >({ index: this.dependencies.resources.aliases.kb, - query: { - bool: { - should: queries.map((query) => ({ - text_expansion: { - 'ml.tokens': { - model_text: query, - model_id: '.elser_model_1', - }, - } as unknown as QueryDslTextExpansionQuery, - })), - filter: [ - ...getAccessQuery({ - user, - namespace, - }), - ], - }, - }, - size: 5, + query, + size: 10, _source: { includes: ['text', 'is_correction', 'labels'], }, @@ -211,7 +227,7 @@ export class KnowledgeBaseService { return { entries: response.hits.hits.map((hit) => ({ ...hit._source!, - score: hit._score, + score: hit._score!, id: hit._id, })), }; diff --git a/x-pack/plugins/observability_ai_assistant/server/service/kb_service/kb_docs/lens.ts b/x-pack/plugins/observability_ai_assistant/server/service/kb_service/kb_docs/lens.ts index e4fdc8969c010..9baf75f6ff552 100644 --- a/x-pack/plugins/observability_ai_assistant/server/service/kb_service/kb_docs/lens.ts +++ b/x-pack/plugins/observability_ai_assistant/server/service/kb_service/kb_docs/lens.ts @@ -6,10 +6,16 @@ */ import dedent from 'dedent'; +import type { Logger } from '@kbn/logging'; import type { ObservabilityAIAssistantService } from '../..'; -export function addLensDocsToKb(service: ObservabilityAIAssistantService) { - service.addToKnowledgeBase([ +export function addLensDocsToKb({ + service, +}: { + service: ObservabilityAIAssistantService; + logger: Logger; +}) { + service.addCategoryToKnowledgeBase('lens', [ { id: 'lens_formulas_how_it_works', texts: [ diff --git a/x-pack/plugins/observability_ai_assistant/server/service/util/get_category_query.ts b/x-pack/plugins/observability_ai_assistant/server/service/util/get_category_query.ts new file mode 100644 index 0000000000000..71b0a93156086 --- /dev/null +++ b/x-pack/plugins/observability_ai_assistant/server/service/util/get_category_query.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export function getCategoryQuery({ contexts }: { contexts?: string[] }) { + const noCategoryFilter = { + bool: { + must_not: { + exists: { + field: 'labels.category', + }, + }, + }, + }; + + if (!contexts) { + return [noCategoryFilter]; + } + + return [ + { + bool: { + should: [ + noCategoryFilter, + { + terms: { + 'labels.category': contexts, + }, + }, + ], + minimum_should_match: 1, + }, + }, + ]; +} From e4105331d32dbc432d4b46d95b610af2f7e7d7da Mon Sep 17 00:00:00 2001 From: Sander Philipse <94373878+sphilipse@users.noreply.github.com> Date: Mon, 25 Sep 2023 17:40:30 +0200 Subject: [PATCH 14/45] [Search] Fix type errors (#167138) ## Summary Fix type issues in the Search plugin. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/enterprise_search/server/index.ts | 4 +--- .../server/lib/crawler/fetch_crawler_multiple_schedules.ts | 4 +--- .../server/lib/crawler/post_crawler_multiple_schedules.ts | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/enterprise_search/server/index.ts b/x-pack/plugins/enterprise_search/server/index.ts index a82d6f18a3b26..3b9372f339acf 100644 --- a/x-pack/plugins/enterprise_search/server/index.ts +++ b/x-pack/plugins/enterprise_search/server/index.ts @@ -8,7 +8,7 @@ import { schema, TypeOf } from '@kbn/config-schema'; import { PluginInitializerContext, PluginConfigDescriptor } from '@kbn/core/server'; -import { EnterpriseSearchPlugin, EnterpriseSearchPluginStart as PluginStart } from './plugin'; +import { EnterpriseSearchPlugin } from './plugin'; export const plugin = (initializerContext: PluginInitializerContext) => { return new EnterpriseSearchPlugin(initializerContext); @@ -54,5 +54,3 @@ export const config: PluginConfigDescriptor = { }; export const CRAWLERS_INDEX = '.ent-search-actastic-crawler2_configurations_v2'; - -export type EnterpriseSearchPluginStart = PluginStart; diff --git a/x-pack/plugins/enterprise_search/server/lib/crawler/fetch_crawler_multiple_schedules.ts b/x-pack/plugins/enterprise_search/server/lib/crawler/fetch_crawler_multiple_schedules.ts index d367e02ed6ab1..04f922e1702ed 100644 --- a/x-pack/plugins/enterprise_search/server/lib/crawler/fetch_crawler_multiple_schedules.ts +++ b/x-pack/plugins/enterprise_search/server/lib/crawler/fetch_crawler_multiple_schedules.ts @@ -7,9 +7,7 @@ import { IScopedClusterClient } from '@kbn/core/server'; -import { Connector } from '@kbn/search-connectors'; - -import { CONNECTORS_INDEX } from '../..'; +import { CONNECTORS_INDEX, Connector } from '@kbn/search-connectors'; const CUSTOM_SCHEDULING = 'custom_scheduling'; diff --git a/x-pack/plugins/enterprise_search/server/lib/crawler/post_crawler_multiple_schedules.ts b/x-pack/plugins/enterprise_search/server/lib/crawler/post_crawler_multiple_schedules.ts index 21d9f8b558800..539495e9556ae 100644 --- a/x-pack/plugins/enterprise_search/server/lib/crawler/post_crawler_multiple_schedules.ts +++ b/x-pack/plugins/enterprise_search/server/lib/crawler/post_crawler_multiple_schedules.ts @@ -7,7 +7,7 @@ import { IScopedClusterClient } from '@kbn/core/server'; -import { CONNECTORS_INDEX } from '../..'; +import { CONNECTORS_INDEX } from '@kbn/search-connectors'; import { CrawlerCustomScheduleMappingServer, From 212bc53b8e42bc92162c8e90b93494a2e83a25d8 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Mon, 25 Sep 2023 10:40:47 -0500 Subject: [PATCH 15/45] skip failing test suite (#167076) --- .../test/profiling_api_integration/tests/has_setup.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/test/profiling_api_integration/tests/has_setup.spec.ts b/x-pack/test/profiling_api_integration/tests/has_setup.spec.ts index 5046eb8c9c556..583cc02908025 100644 --- a/x-pack/test/profiling_api_integration/tests/has_setup.spec.ts +++ b/x-pack/test/profiling_api_integration/tests/has_setup.spec.ts @@ -23,9 +23,9 @@ export default function featureControlsTests({ getService }: FtrProviderContext) const logger = getService('log'); const es = getService('es'); - registry.when('Profiling status check', { config: 'cloud' }, () => { - // Failing: See https://github.com/elastic/kibana/issues/167076 - describe.skip('Profiling is not set up and no data is loaded', () => { + // Failing: See https://github.com/elastic/kibana/issues/167076 + registry.when.skip('Profiling status check', { config: 'cloud' }, () => { + describe('Profiling is not set up and no data is loaded', () => { describe('Admin user', () => { let statusCheck: ProfilingStatus; before(async () => { From e74ec69a0f4ec3635ec259c8cf7afde33dbeb572 Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Mon, 25 Sep 2023 08:55:25 -0700 Subject: [PATCH 16/45] [DOCS] Move preconfigured Torq connector details (#166218) --- .../connector-apis-passthru.asciidoc | 56 +++++++ docs/management/action-types.asciidoc | 24 +-- .../connectors/action-types/torq.asciidoc | 32 +--- docs/management/connectors/index.asciidoc | 4 +- .../pre-configured-connectors.asciidoc | 22 +++ docs/settings/alert-action-settings.asciidoc | 4 + .../plugins/actions/docs/openapi/bundled.json | 138 ++++++++++++++++++ .../plugins/actions/docs/openapi/bundled.yaml | 97 ++++++++++++ .../schemas/config_properties_torq.yaml | 9 ++ .../connector_response_properties.yaml | 1 + .../connector_response_properties_torq.yaml | 31 ++++ .../components/schemas/connector_types.yaml | 1 + .../create_connector_request_torq.yaml | 24 +++ .../schemas/secrets_properties_torq.yaml | 9 ++ .../update_connector_request_torq.yaml | 14 ++ .../s@{spaceid}@api@actions@connector.yaml | 1 + ...}@api@actions@connector@{connectorid}.yaml | 2 + 17 files changed, 427 insertions(+), 42 deletions(-) create mode 100644 x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_torq.yaml create mode 100644 x-pack/plugins/actions/docs/openapi/components/schemas/connector_response_properties_torq.yaml create mode 100644 x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_torq.yaml create mode 100644 x-pack/plugins/actions/docs/openapi/components/schemas/secrets_properties_torq.yaml create mode 100644 x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_torq.yaml diff --git a/docs/api-generated/connectors/connector-apis-passthru.asciidoc b/docs/api-generated/connectors/connector-apis-passthru.asciidoc index a8b429e0b5ae4..b68b4e4ca648f 100644 --- a/docs/api-generated/connectors/connector-apis-passthru.asciidoc +++ b/docs/api-generated/connectors/connector-apis-passthru.asciidoc @@ -1015,6 +1015,7 @@ Any modifications made to this file will be overwritten.
  • config_properties_servicenow - Connector request properties for a ServiceNow ITSM connector
  • config_properties_servicenow_itom - Connector request properties for a ServiceNow ITSM connector
  • config_properties_swimlane - Connector request properties for a Swimlane connector
  • +
  • config_properties_torq - Connector request properties for a Torq connector
  • config_properties_webhook - Connector request properties for a Webhook connector
  • config_properties_xmatters - Connector request properties for an xMatters connector
  • connector_response_properties - Connector response properties
  • @@ -1035,6 +1036,7 @@ Any modifications made to this file will be overwritten.
  • connector_response_properties_swimlane - Connector response properties for a Swimlane connector
  • connector_response_properties_teams - Connector response properties for a Microsoft Teams connector
  • connector_response_properties_tines - Connector response properties for a Tines connector
  • +
  • connector_response_properties_torq - Connector response properties for a Torq connector
  • connector_response_properties_webhook - Connector response properties for a Webhook connector
  • connector_response_properties_xmatters - Connector response properties for an xMatters connector
  • connector_types - Connector types
  • @@ -1056,6 +1058,7 @@ Any modifications made to this file will be overwritten.
  • create_connector_request_swimlane - Create Swimlane connector request
  • create_connector_request_teams - Create Microsoft Teams connector request
  • create_connector_request_tines - Create Tines connector request
  • +
  • create_connector_request_torq - Create Torq connector request
  • create_connector_request_webhook - Create Webhook connector request
  • create_connector_request_xmatters - Create xMatters connector request
  • features -
  • @@ -1106,6 +1109,7 @@ Any modifications made to this file will be overwritten.
  • secrets_properties_slack_webhook - Connector secrets properties for a Webhook Slack connector
  • secrets_properties_swimlane - Connector secrets properties for a Swimlane connector
  • secrets_properties_teams - Connector secrets properties for a Microsoft Teams connector
  • +
  • secrets_properties_torq - Connector secrets properties for a Torq connector
  • secrets_properties_webhook - Connector secrets properties for a Webhook connector
  • secrets_properties_xmatters - Connector secrets properties for an xMatters connector
  • updateConnector_400_response -
  • @@ -1124,6 +1128,7 @@ Any modifications made to this file will be overwritten.
  • update_connector_request_slack_webhook - Update Slack connector request
  • update_connector_request_swimlane - Update Swimlane connector request
  • update_connector_request_teams - Update Microsoft Teams connector request
  • +
  • update_connector_request_torq - Update Torq connector request
  • update_connector_request_webhook - Update Webhook connector request
  • update_connector_request_xmatters - Update xMatters connector request
  • @@ -1529,6 +1534,13 @@ Any modifications made to this file will be overwritten.
    mappings (optional)
    +
    +

    config_properties_torq - Connector request properties for a Torq connector Up

    +
    Defines properties for connectors when type is .torq.
    +
    +
    webhookIntegrationUrl
    String The endpoint URL of the Elastic Security integration in Torq.
    +
    +

    config_properties_webhook - Connector request properties for a Webhook connector Up

    Defines properties for connectors when type is .webhook.
    @@ -1842,6 +1854,22 @@ Any modifications made to this file will be overwritten.
    is_missing_secrets (optional)
    Boolean Indicates whether secrets are missing for the connector. Secrets configuration properties vary depending on the connector type.
    is_preconfigured
    Boolean Indicates whether it is a preconfigured connector. If true, the config and is_missing_secrets properties are omitted from the response.
    is_system_action (optional)
    Boolean Indicates whether the connector is used for system actions.
    +
    name
    String The display name for the connector.
    +
    +
    +
    +

    connector_response_properties_torq - Connector response properties for a Torq connector Up

    +
    +
    +
    config
    +
    connector_type_id
    String The type of connector.
    +
    Enum:
    +
    .torq
    +
    id
    String The identifier for the connector.
    +
    is_deprecated
    Boolean Indicates whether the connector type is deprecated.
    +
    is_missing_secrets (optional)
    Boolean Indicates whether secrets are missing for the connector. Secrets configuration properties vary depending on the connector type.
    +
    is_preconfigured
    Boolean Indicates whether it is a preconfigured connector. If true, the config and is_missing_secrets properties are omitted from the response.
    +
    is_system_action (optional)
    Boolean Indicates whether the connector is used for system actions.
    name
    String The display name for the connector.
    @@ -2093,6 +2121,18 @@ Any modifications made to this file will be overwritten.
    secrets
    map[String, oas_any_type_not_mapped] Defines secrets for connectors when type is .tines.
    +
    +

    create_connector_request_torq - Create Torq connector request Up

    +
    The Torq connector uses a Torq webhook to trigger workflows with Kibana actions.
    +
    +
    config
    +
    connector_type_id
    String The type of connector.
    +
    Enum:
    +
    .torq
    +
    name
    String The display name for the connector.
    +
    secrets
    +
    +

    create_connector_request_webhook - Create Webhook connector request Up

    The Webhook connector uses axios to send a POST or PUT request to a web service.
    @@ -2560,6 +2600,13 @@ Any modifications made to this file will be overwritten.
    webhookUrl
    String The URL of the incoming webhook. If you are using the xpack.actions.allowedHosts setting, add the hostname to the allowed hosts.
    +
    +

    secrets_properties_torq - Connector secrets properties for a Torq connector Up

    +
    Defines secrets for connectors when type is .torq.
    +
    +
    token
    String The secret of the webhook authentication header.
    +
    +

    secrets_properties_webhook - Connector secrets properties for a Webhook connector Up

    Defines secrets for connectors when type is .webhook.
    @@ -2718,6 +2765,15 @@ Any modifications made to this file will be overwritten.
    secrets
    +
    +

    update_connector_request_torq - Update Torq connector request Up

    +
    +
    +
    config
    +
    name
    String The display name for the connector.
    +
    secrets
    +
    +

    update_connector_request_webhook - Update Webhook connector request Up

    diff --git a/docs/management/action-types.asciidoc b/docs/management/action-types.asciidoc index bbaba806386e2..28aa218f3b6c8 100644 --- a/docs/management/action-types.asciidoc +++ b/docs/management/action-types.asciidoc @@ -7,10 +7,18 @@ Connectors provide a central place to store connection information for services [cols="2"] |=== +a| <> + +| Send a request to D3 Security. + a| <> | Send email from your server. +a| <> + +| Send a request to OpenAI. + a| <> | Create an incident in {ibm-r}. @@ -63,6 +71,10 @@ a| <> | Send events to a Tines Story. +a| <> + +| Trigger a Torq workflow. + a| <> | Send a request to a web service. @@ -75,18 +87,6 @@ a| <> | Send actionable alerts to on-call xMatters resources. -a| <> - -| Trigger a Torq workflow. - -a| <> - -| Send a request to OpenAI. - -a| <> - -| Send a request to D3 Security. - |=== [NOTE] diff --git a/docs/management/connectors/action-types/torq.asciidoc b/docs/management/connectors/action-types/torq.asciidoc index 39ef2585e62b9..7b4b9712adcb9 100644 --- a/docs/management/connectors/action-types/torq.asciidoc +++ b/docs/management/connectors/action-types/torq.asciidoc @@ -3,6 +3,10 @@ ++++ Torq ++++ +:frontmatter-description: Add a connector that can use Torq to trigger workflows. +:frontmatter-tags-products: [kibana] +:frontmatter-tags-content-type: [how-to] +:frontmatter-tags-user-goals: [configure] The Torq connector uses a Torq webhook to trigger workflows with Kibana actions. @@ -27,34 +31,6 @@ Torq endpoint URL:: Endpoint URL (webhook) of the Elastic Security integration y Torq authentication header secret:: Secret of the webhook authentication header. -[float] -[[preconfigured-torq-configuration]] -=== Create preconfigured connectors - -If you are running {kib} on-prem, you can define connectors by -adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. -For example: - -[source,yaml] --- -xpack.actions.preconfigured: - my-torq: - name: preconfigured-torq-connector-type - actionTypeId: .torq - config: - webhookIntegrationUrl: https://hooks.torq.io/v1/somehook - secrets: - token: mytorqtoken --- - -Config defines information for the connector type. - -`webhookIntegrationUrl`:: An address that corresponds to **Torq endpoint URL**. - -Secrets defines sensitive information for the connector type. - -`token`:: A string that corresponds to **Torq authentication header secret**. - [float] [[torq-action-configuration]] === Test connectors diff --git a/docs/management/connectors/index.asciidoc b/docs/management/connectors/index.asciidoc index 63de5aca67dca..a30bc26ca2511 100644 --- a/docs/management/connectors/index.asciidoc +++ b/docs/management/connectors/index.asciidoc @@ -1,4 +1,6 @@ +include::action-types/d3security.asciidoc[leveloffset=+1] include::action-types/email.asciidoc[leveloffset=+1] +include::action-types/gen-ai.asciidoc[leveloffset=+1] include::action-types/resilient.asciidoc[leveloffset=+1] include::action-types/index.asciidoc[leveloffset=+1] include::action-types/jira.asciidoc[leveloffset=+1] @@ -16,6 +18,4 @@ include::action-types/torq.asciidoc[leveloffset=+1] include::action-types/webhook.asciidoc[leveloffset=+1] include::action-types/cases-webhook.asciidoc[leveloffset=+1] include::action-types/xmatters.asciidoc[leveloffset=+1] -include::action-types/gen-ai.asciidoc[leveloffset=+1] -include::action-types/d3security.asciidoc[leveloffset=+1] include::pre-configured-connectors.asciidoc[leveloffset=+1] diff --git a/docs/management/connectors/pre-configured-connectors.asciidoc b/docs/management/connectors/pre-configured-connectors.asciidoc index 72f5f78f6e728..1fc679facf423 100644 --- a/docs/management/connectors/pre-configured-connectors.asciidoc +++ b/docs/management/connectors/pre-configured-connectors.asciidoc @@ -113,11 +113,13 @@ Index names must start with `kibana-alert-history-` to take advantage of the pre * <> * <> * <> +* <> * <> * <> * <> * <> * <> +* <> * <> * <> * <> @@ -528,6 +530,26 @@ xpack.actions.preconfigured: <3> Field mappings for properties such as the alert identifer, severity, and rule name. <4> The API authentication token for HTTP basic authentication. NOTE: This value should be stored in the <>. +[float] +[[preconfigured-torq-configuration]] +==== Torq connectors + +The following example creates a <>: + +[source,yaml] +-- +xpack.actions.preconfigured: + my-torq: + name: preconfigured-torq-connector-type + actionTypeId: .torq + config: + webhookIntegrationUrl: https://hooks.torq.io/v1/somehook <1> + secrets: + token: mytorqtoken <2> +-- +<1> The endpoint URL of the Elastic Security integration in Torq. +<2> The secret of the webhook authentication header. + [float] [[preconfigured-webhook-configuration]] ==== Webhook connectors diff --git a/docs/settings/alert-action-settings.asciidoc b/docs/settings/alert-action-settings.asciidoc index c9880bdade4dc..b3cd5777edd69 100644 --- a/docs/settings/alert-action-settings.asciidoc +++ b/docs/settings/alert-action-settings.asciidoc @@ -432,6 +432,9 @@ For an <>, specifies whether it uses HT `xpack.actions.preconfigured..config.viewIncidentUrl`:: For a <>, specifies a URL string with either the external service ID or external service title Mustache variable to view a case in the external system. +`xpack.actions.preconfigured..config.webhookIntegrationUrl`:: +For a <>, specifies the endpoint URL of the Elastic Security integration in Torq. + `xpack.actions.preconfigured..name`:: The name of the preconfigured connector. @@ -492,6 +495,7 @@ A token secret that varies by connector: -- * For a <>, specifies the D3 Security token. * For a <>, specifies the Slack bot user OAuth token. +* For a <>, specifies the secret of the webhook authentication header. -- `xpack.actions.preconfigured..secrets.user`:: diff --git a/x-pack/plugins/actions/docs/openapi/bundled.json b/x-pack/plugins/actions/docs/openapi/bundled.json index f79bb3ca9c0fe..4039ab6b5a0de 100644 --- a/x-pack/plugins/actions/docs/openapi/bundled.json +++ b/x-pack/plugins/actions/docs/openapi/bundled.json @@ -111,6 +111,9 @@ { "$ref": "#/components/schemas/create_connector_request_tines" }, + { + "$ref": "#/components/schemas/create_connector_request_torq" + }, { "$ref": "#/components/schemas/create_connector_request_webhook" }, @@ -389,6 +392,9 @@ { "$ref": "#/components/schemas/create_connector_request_tines" }, + { + "$ref": "#/components/schemas/create_connector_request_torq" + }, { "$ref": "#/components/schemas/create_connector_request_webhook" }, @@ -508,6 +514,9 @@ { "$ref": "#/components/schemas/update_connector_request_teams" }, + { + "$ref": "#/components/schemas/update_connector_request_torq" + }, { "$ref": "#/components/schemas/update_connector_request_webhook" }, @@ -2829,6 +2838,66 @@ } } }, + "config_properties_torq": { + "title": "Connector request properties for a Torq connector", + "description": "Defines properties for connectors when type is `.torq`.", + "type": "object", + "required": [ + "webhookIntegrationUrl" + ], + "properties": { + "webhookIntegrationUrl": { + "description": "The endpoint URL of the Elastic Security integration in Torq.", + "type": "string" + } + } + }, + "secrets_properties_torq": { + "title": "Connector secrets properties for a Torq connector", + "description": "Defines secrets for connectors when type is `.torq`.", + "type": "object", + "required": [ + "token" + ], + "properties": { + "token": { + "description": "The secret of the webhook authentication header.", + "type": "string" + } + } + }, + "create_connector_request_torq": { + "title": "Create Torq connector request", + "description": "The Torq connector uses a Torq webhook to trigger workflows with Kibana actions.\n", + "type": "object", + "required": [ + "config", + "connector_type_id", + "name", + "secrets" + ], + "properties": { + "config": { + "$ref": "#/components/schemas/config_properties_torq" + }, + "connector_type_id": { + "type": "string", + "description": "The type of connector.", + "enum": [ + ".torq" + ], + "example": ".torq" + }, + "name": { + "type": "string", + "description": "The display name for the connector.", + "example": "my-connector" + }, + "secrets": { + "$ref": "#/components/schemas/secrets_properties_torq" + } + } + }, "config_properties_webhook": { "title": "Connector request properties for a Webhook connector", "description": "Defines properties for connectors when type is `.webhook`.", @@ -3776,6 +3845,50 @@ } } }, + "connector_response_properties_torq": { + "title": "Connector response properties for a Torq connector", + "type": "object", + "required": [ + "config", + "connector_type_id", + "id", + "is_deprecated", + "is_preconfigured", + "name" + ], + "properties": { + "config": { + "$ref": "#/components/schemas/config_properties_torq" + }, + "connector_type_id": { + "type": "string", + "description": "The type of connector.", + "enum": [ + ".torq" + ] + }, + "id": { + "type": "string", + "description": "The identifier for the connector." + }, + "is_deprecated": { + "$ref": "#/components/schemas/is_deprecated" + }, + "is_missing_secrets": { + "$ref": "#/components/schemas/is_missing_secrets" + }, + "is_preconfigured": { + "$ref": "#/components/schemas/is_preconfigured" + }, + "is_system_action": { + "$ref": "#/components/schemas/is_system_action" + }, + "name": { + "type": "string", + "description": "The display name for the connector." + } + } + }, "connector_response_properties_webhook": { "title": "Connector response properties for a Webhook connector", "type": "object", @@ -3919,6 +4032,9 @@ { "$ref": "#/components/schemas/connector_response_properties_tines" }, + { + "$ref": "#/components/schemas/connector_response_properties_torq" + }, { "$ref": "#/components/schemas/connector_response_properties_webhook" }, @@ -4221,6 +4337,27 @@ } } }, + "update_connector_request_torq": { + "title": "Update Torq connector request", + "type": "object", + "required": [ + "config", + "name", + "secrets" + ], + "properties": { + "config": { + "$ref": "#/components/schemas/config_properties_torq" + }, + "name": { + "type": "string", + "description": "The display name for the connector." + }, + "secrets": { + "$ref": "#/components/schemas/secrets_properties_torq" + } + } + }, "update_connector_request_webhook": { "title": "Update Webhook connector request", "type": "object", @@ -4286,6 +4423,7 @@ ".swimlane", ".teams", ".tines", + ".torq", ".webhook", ".xmatters" ], diff --git a/x-pack/plugins/actions/docs/openapi/bundled.yaml b/x-pack/plugins/actions/docs/openapi/bundled.yaml index ed97fb7f31233..9d1842c4dace9 100644 --- a/x-pack/plugins/actions/docs/openapi/bundled.yaml +++ b/x-pack/plugins/actions/docs/openapi/bundled.yaml @@ -55,6 +55,7 @@ paths: - $ref: '#/components/schemas/create_connector_request_swimlane' - $ref: '#/components/schemas/create_connector_request_teams' - $ref: '#/components/schemas/create_connector_request_tines' + - $ref: '#/components/schemas/create_connector_request_torq' - $ref: '#/components/schemas/create_connector_request_webhook' - $ref: '#/components/schemas/create_connector_request_xmatters' discriminator: @@ -208,6 +209,7 @@ paths: - $ref: '#/components/schemas/create_connector_request_swimlane' - $ref: '#/components/schemas/create_connector_request_teams' - $ref: '#/components/schemas/create_connector_request_tines' + - $ref: '#/components/schemas/create_connector_request_torq' - $ref: '#/components/schemas/create_connector_request_webhook' - $ref: '#/components/schemas/create_connector_request_xmatters' discriminator: @@ -264,6 +266,7 @@ paths: - $ref: '#/components/schemas/update_connector_request_slack_webhook' - $ref: '#/components/schemas/update_connector_request_swimlane' - $ref: '#/components/schemas/update_connector_request_teams' + - $ref: '#/components/schemas/update_connector_request_torq' - $ref: '#/components/schemas/update_connector_request_webhook' - $ref: '#/components/schemas/update_connector_request_xmatters' examples: @@ -1916,6 +1919,51 @@ components: example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_tines' + config_properties_torq: + title: Connector request properties for a Torq connector + description: Defines properties for connectors when type is `.torq`. + type: object + required: + - webhookIntegrationUrl + properties: + webhookIntegrationUrl: + description: The endpoint URL of the Elastic Security integration in Torq. + type: string + secrets_properties_torq: + title: Connector secrets properties for a Torq connector + description: Defines secrets for connectors when type is `.torq`. + type: object + required: + - token + properties: + token: + description: The secret of the webhook authentication header. + type: string + create_connector_request_torq: + title: Create Torq connector request + description: | + The Torq connector uses a Torq webhook to trigger workflows with Kibana actions. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/config_properties_torq' + connector_type_id: + type: string + description: The type of connector. + enum: + - .torq + example: .torq + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/secrets_properties_torq' config_properties_webhook: title: Connector request properties for a Webhook connector description: Defines properties for connectors when type is `.webhook`. @@ -2626,6 +2674,38 @@ components: name: type: string description: The display name for the connector. + connector_response_properties_torq: + title: Connector response properties for a Torq connector + type: object + required: + - config + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/config_properties_torq' + connector_type_id: + type: string + description: The type of connector. + enum: + - .torq + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/is_preconfigured' + is_system_action: + $ref: '#/components/schemas/is_system_action' + name: + type: string + description: The display name for the connector. connector_response_properties_webhook: title: Connector response properties for a Webhook connector type: object @@ -2711,6 +2791,7 @@ components: - $ref: '#/components/schemas/connector_response_properties_swimlane' - $ref: '#/components/schemas/connector_response_properties_teams' - $ref: '#/components/schemas/connector_response_properties_tines' + - $ref: '#/components/schemas/connector_response_properties_torq' - $ref: '#/components/schemas/connector_response_properties_webhook' - $ref: '#/components/schemas/connector_response_properties_xmatters' discriminator: @@ -2922,6 +3003,21 @@ components: description: The display name for the connector. secrets: $ref: '#/components/schemas/secrets_properties_teams' + update_connector_request_torq: + title: Update Torq connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/config_properties_torq' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/secrets_properties_torq' update_connector_request_webhook: title: Update Webhook connector request type: object @@ -2975,6 +3071,7 @@ components: - .swimlane - .teams - .tines + - .torq - .webhook - .xmatters example: .server-log diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_torq.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_torq.yaml new file mode 100644 index 0000000000000..06808a37a75fc --- /dev/null +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_torq.yaml @@ -0,0 +1,9 @@ +title: Connector request properties for a Torq connector +description: Defines properties for connectors when type is `.torq`. +type: object +required: + - webhookIntegrationUrl +properties: + webhookIntegrationUrl: + description: The endpoint URL of the Elastic Security integration in Torq. + type: string \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/connector_response_properties.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/connector_response_properties.yaml index 334fe3fa5cdb3..edef270fd75ae 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/connector_response_properties.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/connector_response_properties.yaml @@ -18,6 +18,7 @@ oneOf: - $ref: 'connector_response_properties_swimlane.yaml' - $ref: 'connector_response_properties_teams.yaml' - $ref: 'connector_response_properties_tines.yaml' + - $ref: 'connector_response_properties_torq.yaml' - $ref: 'connector_response_properties_webhook.yaml' - $ref: 'connector_response_properties_xmatters.yaml' discriminator: diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/connector_response_properties_torq.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/connector_response_properties_torq.yaml new file mode 100644 index 0000000000000..135d5e9db6cb4 --- /dev/null +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/connector_response_properties_torq.yaml @@ -0,0 +1,31 @@ +title: Connector response properties for a Torq connector +type: object +required: + - config + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name +properties: + config: + $ref: 'config_properties_torq.yaml' + connector_type_id: + type: string + description: The type of connector. + enum: + - .torq + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: 'is_deprecated.yaml' + is_missing_secrets: + $ref: 'is_missing_secrets.yaml' + is_preconfigured: + $ref: 'is_preconfigured.yaml' + is_system_action: + $ref: 'is_system_action.yaml' + name: + type: string + description: The display name for the connector. diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/connector_types.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/connector_types.yaml index 2bbc9f5dabac4..687648acd7141 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/connector_types.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/connector_types.yaml @@ -20,6 +20,7 @@ enum: - .swimlane - .teams - .tines + - .torq - .webhook - .xmatters example: .server-log \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_torq.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_torq.yaml new file mode 100644 index 0000000000000..934f9c9c1b395 --- /dev/null +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_torq.yaml @@ -0,0 +1,24 @@ +title: Create Torq connector request +description: > + The Torq connector uses a Torq webhook to trigger workflows with Kibana actions. +type: object +required: + - config + - connector_type_id + - name + - secrets +properties: + config: + $ref: 'config_properties_torq.yaml' + connector_type_id: + type: string + description: The type of connector. + enum: + - .torq + example: .torq + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: 'secrets_properties_torq.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/secrets_properties_torq.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/secrets_properties_torq.yaml new file mode 100644 index 0000000000000..ab79a0f672b42 --- /dev/null +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/secrets_properties_torq.yaml @@ -0,0 +1,9 @@ +title: Connector secrets properties for a Torq connector +description: Defines secrets for connectors when type is `.torq`. +type: object +required: + - token +properties: + token: + description: The secret of the webhook authentication header. + type: string \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_torq.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_torq.yaml new file mode 100644 index 0000000000000..f82de22f3e27b --- /dev/null +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_torq.yaml @@ -0,0 +1,14 @@ +title: Update Torq connector request +type: object +required: + - config + - name + - secrets +properties: + config: + $ref: 'config_properties_torq.yaml' + name: + type: string + description: The display name for the connector. + secrets: + $ref: 'secrets_properties_torq.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector.yaml b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector.yaml index f32def50706b2..62f2e1821eb8f 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector.yaml @@ -34,6 +34,7 @@ post: - $ref: '../components/schemas/create_connector_request_swimlane.yaml' - $ref: '../components/schemas/create_connector_request_teams.yaml' - $ref: '../components/schemas/create_connector_request_tines.yaml' + - $ref: '../components/schemas/create_connector_request_torq.yaml' - $ref: '../components/schemas/create_connector_request_webhook.yaml' - $ref: '../components/schemas/create_connector_request_xmatters.yaml' discriminator: diff --git a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml index c6a2447c251a2..ad93b5076639a 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml @@ -118,6 +118,7 @@ post: - $ref: '../components/schemas/create_connector_request_swimlane.yaml' - $ref: '../components/schemas/create_connector_request_teams.yaml' - $ref: '../components/schemas/create_connector_request_tines.yaml' + - $ref: '../components/schemas/create_connector_request_torq.yaml' - $ref: '../components/schemas/create_connector_request_webhook.yaml' - $ref: '../components/schemas/create_connector_request_xmatters.yaml' discriminator: @@ -176,6 +177,7 @@ put: - $ref: '../components/schemas/update_connector_request_swimlane.yaml' - $ref: '../components/schemas/update_connector_request_teams.yaml' # - $ref: '../components/schemas/update_connector_request_tines.yaml' + - $ref: '../components/schemas/update_connector_request_torq.yaml' - $ref: '../components/schemas/update_connector_request_webhook.yaml' - $ref: '../components/schemas/update_connector_request_xmatters.yaml' examples: From 2f1b6ac89640e494ec592eee92a0471674ff5526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20FOUCRET?= Date: Mon, 25 Sep 2023 18:02:33 +0200 Subject: [PATCH 17/45] [Guided onboarding] Updating search solution items. (#166953) --- .../__snapshots__/guide_cards.test.tsx.snap | 76 +++++++++---------- .../landing_page/guide_cards.constants.tsx | 42 +++++----- .../translations/translations/fr-FR.json | 2 +- .../translations/translations/ja-JP.json | 2 +- .../translations/translations/zh-CN.json | 2 +- 5 files changed, 62 insertions(+), 62 deletions(-) diff --git a/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_cards.test.tsx.snap b/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_cards.test.tsx.snap index ba2969ab4a0b3..f971ca2c40bbb 100644 --- a/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_cards.test.tsx.snap +++ b/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_cards.test.tsx.snap @@ -18,14 +18,20 @@ exports[`guide cards snapshots should render all cards 1`] = ` activeFilter="all" card={ Object { - "icon": "vector", - "navigateTo": Object { - "appId": "enterpriseSearchVectorSearch", - }, + "guideId": "databaseSearch", + "icon": "database", "order": 1, "solution": "search", - "telemetryId": "onboarding--search--vector", - "title": "Set up vector search", + "telemetryId": "onboarding--search--database", + "title": , + } + } + />, } } guidesState={Array []} @@ -44,14 +50,14 @@ exports[`guide cards snapshots should render all cards 1`] = ` activeFilter="all" card={ Object { - "icon": "magnifyWithPlus", + "icon": "vector", "navigateTo": Object { - "appId": "enterpriseSearchAISearch", + "appId": "enterpriseSearchVectorSearch", }, "order": 4, "solution": "search", - "telemetryId": "onboarding--search--semantic", - "title": "Build a semantic search experience", + "telemetryId": "onboarding--search--vector", + "title": "Set up vector search", } } guidesState={Array []} @@ -70,20 +76,14 @@ exports[`guide cards snapshots should render all cards 1`] = ` activeFilter="all" card={ Object { - "guideId": "appSearch", - "icon": "wrench", + "icon": "magnifyWithPlus", + "navigateTo": Object { + "appId": "enterpriseSearchAISearch", + }, "order": 7, "solution": "search", - "telemetryId": "onboarding--search--application", - "title": , - } - } - />, + "telemetryId": "onboarding--search--ai", + "title": "Build an AI-powered search experience", } } guidesState={Array []} @@ -102,12 +102,20 @@ exports[`guide cards snapshots should render all cards 1`] = ` activeFilter="all" card={ Object { - "guideId": "websiteSearch", - "icon": "search", + "guideId": "appSearch", + "icon": "wrench", "order": 10, "solution": "search", - "telemetryId": "onboarding--search--website", - "title": "Add search to my website", + "telemetryId": "onboarding--search--application", + "title": , + } + } + />, } } guidesState={Array []} @@ -126,20 +134,12 @@ exports[`guide cards snapshots should render all cards 1`] = ` activeFilter="all" card={ Object { - "guideId": "databaseSearch", - "icon": "database", + "guideId": "websiteSearch", + "icon": "search", "order": 13, "solution": "search", - "telemetryId": "onboarding--search--database", - "title": , - } - } - />, + "telemetryId": "onboarding--search--website", + "title": "Add search to my website", } } guidesState={Array []} diff --git a/packages/kbn-guided-onboarding/src/components/landing_page/guide_cards.constants.tsx b/packages/kbn-guided-onboarding/src/components/landing_page/guide_cards.constants.tsx index c624f31d2848a..f570f5ea3b87b 100644 --- a/packages/kbn-guided-onboarding/src/components/landing_page/guide_cards.constants.tsx +++ b/packages/kbn-guided-onboarding/src/components/landing_page/guide_cards.constants.tsx @@ -31,6 +31,22 @@ export interface GuideCardConstants { } export const guideCards: GuideCardConstants[] = [ + { + solution: 'search', + icon: 'database', + title: ( + , + }} + /> + ), + guideId: 'databaseSearch', + telemetryId: 'onboarding--search--database', + order: 1, + }, { solution: 'search', icon: 'vector', @@ -41,19 +57,19 @@ export const guideCards: GuideCardConstants[] = [ appId: 'enterpriseSearchVectorSearch', }, telemetryId: 'onboarding--search--vector', - order: 1, + order: 4, }, { solution: 'search', icon: 'magnifyWithPlus', title: i18n.translate('guidedOnboardingPackage.gettingStarted.cards.aiSearch.title', { - defaultMessage: 'Build a semantic search experience', + defaultMessage: 'Build an AI-powered search experience', }), navigateTo: { appId: 'enterpriseSearchAISearch', }, - telemetryId: 'onboarding--search--semantic', - order: 4, + telemetryId: 'onboarding--search--ai', + order: 7, }, { solution: 'search', @@ -69,7 +85,7 @@ export const guideCards: GuideCardConstants[] = [ ), guideId: 'appSearch', telemetryId: 'onboarding--search--application', - order: 7, + order: 10, }, { solution: 'search', @@ -79,22 +95,6 @@ export const guideCards: GuideCardConstants[] = [ }), guideId: 'websiteSearch', telemetryId: 'onboarding--search--website', - order: 10, - }, - { - solution: 'search', - icon: 'database', - title: ( - , - }} - /> - ), - guideId: 'databaseSearch', - telemetryId: 'onboarding--search--database', order: 13, }, { diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 150f72792a861..0e167e1ce60d3 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -3212,7 +3212,7 @@ "guidedOnboardingPackage.gettingStarted.cards.progressLabel": "{numberCompleteSteps} รฉtape(s) terminรฉe(s) sur {numberSteps}", "guidedOnboardingPackage.gettingStarted.cards.siemSecurity.title": "Dรฉtecter les menaces dans {lineBreak} mes donnรฉes avec SIEM", "guidedOnboardingPackage.gettingStarted.cards.completeLabel": "Guide terminรฉ", - "guidedOnboardingPackage.gettingStarted.cards.aiSearch.title": "Crรฉer une expรฉrience de recherche sรฉmantique", + "guidedOnboardingPackage.gettingStarted.cards.aiSearch.title": "Crรฉer une expรฉrience de recherche basรฉe sur l'IA", "guidedOnboardingPackage.gettingStarted.cards.hostsObservability.title": "Monitorer mes indicateurs d'hรดte", "guidedOnboardingPackage.gettingStarted.cards.kubernetesObservability.title": "Monitorer les clusters Kubernetes", "guidedOnboardingPackage.gettingStarted.cards.logsObservability.title": "Collecter et analyser mes logs", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 41096d8c2e990..f0e47690da767 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -3227,7 +3227,7 @@ "guidedOnboardingPackage.gettingStarted.cards.progressLabel": "{numberSteps}ใ‚นใƒ†ใƒƒใƒ—ไธญ{numberCompleteSteps}ใ‚นใƒ†ใƒƒใƒ—ๅฎŒไบ†", "guidedOnboardingPackage.gettingStarted.cards.siemSecurity.title": "SIEMใง{lineBreak}ใƒ‡ใƒผใ‚ฟใฎ่„…ๅจใ‚’ๆคœๅ‡บ", "guidedOnboardingPackage.gettingStarted.cards.completeLabel": "ใ‚ฌใ‚คใƒ‰ๅฎŒไบ†", - "guidedOnboardingPackage.gettingStarted.cards.aiSearch.title": "ใ‚ปใƒžใƒณใƒ†ใ‚ฃใƒƒใ‚ฏๆคœ็ดขใ‚จใ‚ฏใ‚นใƒšใƒชใ‚จใƒณใ‚นใ‚’ๆง‹็ฏ‰", + "guidedOnboardingPackage.gettingStarted.cards.aiSearch.title": "AI ใ‚’ๆดป็”จใ—ใŸๆคœ็ดขใ‚จใ‚ฏใ‚นใƒšใƒชใ‚จใƒณใ‚นใ‚’ๆง‹็ฏ‰ใ™ใ‚‹", "guidedOnboardingPackage.gettingStarted.cards.hostsObservability.title": "ใƒ›ใ‚นใƒˆใƒกใƒˆใƒชใƒƒใ‚ฏใ‚’็›ฃ่ฆ–", "guidedOnboardingPackage.gettingStarted.cards.kubernetesObservability.title": "Kubernetesใ‚ฏใƒฉใ‚นใ‚ฟใƒผใฎ็›ฃ่ฆ–", "guidedOnboardingPackage.gettingStarted.cards.logsObservability.title": "ใƒญใ‚ฐใ‚’ๅŽ้›†ใ—ใฆๅˆ†ๆž", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index b17bf98b8ad3a..17beacb3184e2 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -3226,7 +3226,7 @@ "guidedOnboardingPackage.gettingStarted.cards.progressLabel": "ๅทฒๅฎŒๆˆ {numberCompleteSteps} ไธช๏ผˆๅ…ฑ {numberSteps} ไธช๏ผ‰ๆญฅ้ชค", "guidedOnboardingPackage.gettingStarted.cards.siemSecurity.title": "้€š่ฟ‡ SIEM{lineBreak}ๅœจๆˆ‘็š„ๆ•ฐๆฎไธญๆฃ€ๆต‹ๅจ่ƒ", "guidedOnboardingPackage.gettingStarted.cards.completeLabel": "ๆŒ‡ๅ—ๅฎŒๆˆ", - "guidedOnboardingPackage.gettingStarted.cards.aiSearch.title": "ๆž„ๅปบ่ฏญไน‰ๆœ็ดขไฝ“้ชŒ", + "guidedOnboardingPackage.gettingStarted.cards.aiSearch.title": "ๆ‰“้€ ไบบๅทฅๆ™บ่ƒฝ้ฉฑๅŠจ็š„ๆœ็ดขไฝ“้ชŒ", "guidedOnboardingPackage.gettingStarted.cards.hostsObservability.title": "็›‘ๆต‹ๆˆ‘็š„ไธปๆœบๆŒ‡ๆ ‡", "guidedOnboardingPackage.gettingStarted.cards.kubernetesObservability.title": "็›‘ๆต‹ Kubernetes ้›†็พค", "guidedOnboardingPackage.gettingStarted.cards.logsObservability.title": "ๆ”ถ้›†ๅนถๅˆ†ๆžๆˆ‘็š„ๆ—ฅๅฟ—", From 2bce7bbcbeba1d093ee4825d0de8d6d3b78c7bc4 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Mon, 25 Sep 2023 18:15:35 +0200 Subject: [PATCH 18/45] [ML] Shared service for elastic curated models (#167000) ## Summary Adds a shared service for elastic curated models. The first use case is to provide a default/recommended ELSER version based on the hardware of the current cluster. #### Why? In 8.11 we'll provide a platform-specific version of the ELSER v2 alongside the portable one. At the moment several solutions refer to ELSER for download/inference purposes with a `.elser_model_1` constant. Starting 8.11 the model ID will vary, so using the `ElastcModels` service allows retrieving the recommended version of ELSER for the current cluster without any changes by solution teams in future releases. It is still possible to request an older version of the model if necessary. #### Implementation - Adds a new Kibana API endpoint `/trained_models/model_downloads` that provides a list of model definitions, with the `default` and `recommended` flags. - Adds a new Kibana API endpoint `/trained_models/elser_config` that provides an ELSER configuration based on the cluster architecture. - `getELSER` method is exposed from the plugin `setup` server-side as part of our shared services and plugin `start` client-side. ### Checklist - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- .../packages/ml/trained_models_utils/index.ts | 6 ++ .../src/constants/trained_models.ts | 53 ++++++++++- .../services/elastic_models_service.ts | 23 +++++ .../services/get_shared_ml_services.ts | 25 ++++++ .../application/services/http_service.ts | 64 +------------ .../services/ml_api_service/trained_models.ts | 26 +++++- x-pack/plugins/ml/public/mocks.ts | 18 +++- x-pack/plugins/ml/public/plugin.ts | 10 +++ .../apidoc_scripts/apidoc_config/apidoc.json | 2 + .../model_management/model_provider.test.ts | 88 ++++++++++++++++++ .../model_management/models_provider.ts | 89 ++++++++++++++++++- x-pack/plugins/ml/server/plugin.ts | 2 +- .../server/routes/schemas/inference_schema.ts | 4 + .../ml/server/routes/trained_models.ts | 86 ++++++++++++++++-- .../providers/trained_models.ts | 16 +++- .../server/shared_services/shared_services.ts | 2 +- x-pack/plugins/ml/tsconfig.json | 1 + 17 files changed, 438 insertions(+), 77 deletions(-) create mode 100644 x-pack/plugins/ml/public/application/services/elastic_models_service.ts create mode 100644 x-pack/plugins/ml/public/application/services/get_shared_ml_services.ts create mode 100644 x-pack/plugins/ml/server/models/model_management/model_provider.test.ts diff --git a/x-pack/packages/ml/trained_models_utils/index.ts b/x-pack/packages/ml/trained_models_utils/index.ts index ba67911f3f8ab..22b808bdc7b5e 100644 --- a/x-pack/packages/ml/trained_models_utils/index.ts +++ b/x-pack/packages/ml/trained_models_utils/index.ts @@ -14,4 +14,10 @@ export { type DeploymentState, type SupportedPytorchTasksType, type TrainedModelType, + ELASTIC_MODEL_DEFINITIONS, + type ElasticModelId, + type ModelDefinition, + type ModelDefinitionResponse, + type ElserVersion, + type GetElserOptions, } from './src/constants/trained_models'; diff --git a/x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts b/x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts index 86b88f51a66c4..4580330119ddd 100644 --- a/x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts +++ b/x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts @@ -46,8 +46,9 @@ export const BUILT_IN_MODEL_TAG = 'prepackaged'; export const ELASTIC_MODEL_TAG = 'elastic'; -export const ELASTIC_MODEL_DEFINITIONS = { +export const ELASTIC_MODEL_DEFINITIONS: Record = Object.freeze({ '.elser_model_1': { + version: 1, config: { input: { field_names: ['text_field'], @@ -57,7 +58,49 @@ export const ELASTIC_MODEL_DEFINITIONS = { defaultMessage: 'Elastic Learned Sparse EncodeR v1 (Tech Preview)', }), }, -} as const; + '.elser_model_2_SNAPSHOT': { + version: 2, + default: true, + config: { + input: { + field_names: ['text_field'], + }, + }, + description: i18n.translate('xpack.ml.trainedModels.modelsList.elserV2Description', { + defaultMessage: 'Elastic Learned Sparse EncodeR v2 (Tech Preview)', + }), + }, + '.elser_model_2_linux-x86_64_SNAPSHOT': { + version: 2, + os: 'Linux', + arch: 'amd64', + config: { + input: { + field_names: ['text_field'], + }, + }, + description: i18n.translate('xpack.ml.trainedModels.modelsList.elserV2x86Description', { + defaultMessage: + 'Elastic Learned Sparse EncodeR v2, optimized for linux-x86_64 (Tech Preview)', + }), + }, +} as const); + +export interface ModelDefinition { + version: number; + config: object; + description: string; + os?: string; + arch?: string; + default?: boolean; + recommended?: boolean; +} + +export type ModelDefinitionResponse = ModelDefinition & { + name: string; +}; + +export type ElasticModelId = keyof typeof ELASTIC_MODEL_DEFINITIONS; export const MODEL_STATE = { ...DEPLOYMENT_STATE, @@ -66,3 +109,9 @@ export const MODEL_STATE = { } as const; export type ModelState = typeof MODEL_STATE[keyof typeof MODEL_STATE] | null; + +export type ElserVersion = 1 | 2; + +export interface GetElserOptions { + version?: ElserVersion; +} diff --git a/x-pack/plugins/ml/public/application/services/elastic_models_service.ts b/x-pack/plugins/ml/public/application/services/elastic_models_service.ts new file mode 100644 index 0000000000000..2591fb6d82e7d --- /dev/null +++ b/x-pack/plugins/ml/public/application/services/elastic_models_service.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 type { ModelDefinitionResponse, GetElserOptions } from '@kbn/ml-trained-models-utils'; +import { type TrainedModelsApiService } from './ml_api_service/trained_models'; + +export class ElasticModels { + constructor(private readonly trainedModels: TrainedModelsApiService) {} + + /** + * Provides an ELSER model name and configuration for download based on the current cluster architecture. + * The current default version is 2. If running on Cloud it returns the Linux x86_64 optimized version. + * If any of the ML nodes run a different OS rather than Linux, or the CPU architecture isn't x86_64, + * a portable version of the model is returned. + */ + public async getELSER(options?: GetElserOptions): Promise { + return await this.trainedModels.getElserConfig(options); + } +} diff --git a/x-pack/plugins/ml/public/application/services/get_shared_ml_services.ts b/x-pack/plugins/ml/public/application/services/get_shared_ml_services.ts new file mode 100644 index 0000000000000..23ac82737044f --- /dev/null +++ b/x-pack/plugins/ml/public/application/services/get_shared_ml_services.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { type HttpStart } from '@kbn/core-http-browser'; +import { ElasticModels } from './elastic_models_service'; +import { HttpService } from './http_service'; +import { mlApiServicesProvider } from './ml_api_service'; + +export type MlSharedServices = ReturnType; + +/** + * Provides ML services exposed from the plugin start. + */ +export function getMlSharedServices(httpStart: HttpStart) { + const httpService = new HttpService(httpStart); + const mlApiServices = mlApiServicesProvider(httpService); + + return { + elasticModels: new ElasticModels(mlApiServices.trainedModels), + }; +} diff --git a/x-pack/plugins/ml/public/application/services/http_service.ts b/x-pack/plugins/ml/public/application/services/http_service.ts index c43b6126f147f..cd283c5d58652 100644 --- a/x-pack/plugins/ml/public/application/services/http_service.ts +++ b/x-pack/plugins/ml/public/application/services/http_service.ts @@ -6,7 +6,7 @@ */ import { Observable } from 'rxjs'; -import { HttpFetchOptionsWithPath, HttpFetchOptions, HttpStart } from '@kbn/core/public'; +import type { HttpFetchOptionsWithPath, HttpFetchOptions, HttpStart } from '@kbn/core/public'; import { getHttp } from '../util/dependency_cache'; function getResultHeaders(headers: HeadersInit) { @@ -59,68 +59,6 @@ export async function http(options: HttpFetchOptionsWithPath): Promise { return getHttp().fetch(path, fetchOptions); } -/** - * Function for making HTTP requests to Kibana's backend which returns an Observable - * with request cancellation support. - * - * @deprecated use {@link HttpService} instead - */ -export function http$(options: HttpFetchOptionsWithPath): Observable { - const { path, fetchOptions } = getFetchOptions(options); - return fromHttpHandler(path, fetchOptions); -} - -/** - * Creates an Observable from Kibana's HttpHandler. - */ -function fromHttpHandler(input: string, init?: RequestInit): Observable { - return new Observable((subscriber) => { - const controller = new AbortController(); - const signal = controller.signal; - - let abortable = true; - let unsubscribed = false; - - if (init?.signal) { - if (init.signal.aborted) { - controller.abort(); - } else { - init.signal.addEventListener('abort', () => { - if (!signal.aborted) { - controller.abort(); - } - }); - } - } - - const perSubscriberInit: RequestInit = { - ...(init ? init : {}), - signal, - }; - - getHttp() - .fetch(input, perSubscriberInit) - .then((response) => { - abortable = false; - subscriber.next(response); - subscriber.complete(); - }) - .catch((err) => { - abortable = false; - if (!unsubscribed) { - subscriber.error(err); - } - }); - - return () => { - unsubscribed = true; - if (abortable) { - controller.abort(); - } - }; - }); -} - /** * ML Http Service */ diff --git a/x-pack/plugins/ml/public/application/services/ml_api_service/trained_models.ts b/x-pack/plugins/ml/public/application/services/ml_api_service/trained_models.ts index e6b9c1a5badc3..c10867af0011b 100644 --- a/x-pack/plugins/ml/public/application/services/ml_api_service/trained_models.ts +++ b/x-pack/plugins/ml/public/application/services/ml_api_service/trained_models.ts @@ -6,11 +6,12 @@ */ import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { IngestPipeline } from '@elastic/elasticsearch/lib/api/types'; +import type { IngestPipeline } from '@elastic/elasticsearch/lib/api/types'; import { useMemo } from 'react'; import type { HttpFetchQuery } from '@kbn/core/public'; import type { ErrorType } from '@kbn/ml-error-utils'; +import type { GetElserOptions, ModelDefinitionResponse } from '@kbn/ml-trained-models-utils'; import { ML_INTERNAL_BASE_PATH } from '../../../../common/constants/app'; import type { MlSavedObjectType } from '../../../../common/types/saved_objects'; import { HttpService } from '../http_service'; @@ -57,6 +58,29 @@ export interface InferenceStatsResponse { */ export function trainedModelsApiProvider(httpService: HttpService) { return { + /** + * Fetches the trained models list available for download. + */ + getTrainedModelDownloads() { + return httpService.http({ + path: `${ML_INTERNAL_BASE_PATH}/trained_models/model_downloads`, + method: 'GET', + version: '1', + }); + }, + + /** + * Gets ELSER config for download based on the cluster OS and CPU architecture. + */ + getElserConfig(options?: GetElserOptions) { + return httpService.http({ + path: `${ML_INTERNAL_BASE_PATH}/trained_models/elser_config`, + method: 'GET', + ...(options ? { query: options as HttpFetchQuery } : {}), + version: '1', + }); + }, + /** * Fetches configuration information for a trained inference model. * @param modelId - Model ID, collection of Model IDs or Model ID pattern. diff --git a/x-pack/plugins/ml/public/mocks.ts b/x-pack/plugins/ml/public/mocks.ts index 13f8952dbad21..77cdefdb2f1c9 100644 --- a/x-pack/plugins/ml/public/mocks.ts +++ b/x-pack/plugins/ml/public/mocks.ts @@ -6,7 +6,8 @@ */ import { sharePluginMock } from '@kbn/share-plugin/public/mocks'; -import { MlPluginSetup, MlPluginStart } from './plugin'; +import { type ElasticModels } from './application/services/elastic_models_service'; +import type { MlPluginSetup, MlPluginStart } from './plugin'; const createSetupContract = (): jest.Mocked => { return { @@ -17,6 +18,21 @@ const createSetupContract = (): jest.Mocked => { const createStartContract = (): jest.Mocked => { return { locator: sharePluginMock.createLocator(), + elasticModels: { + getELSER: jest.fn(() => + Promise.resolve({ + version: 2, + default: true, + config: { + input: { + field_names: ['text_field'], + }, + }, + description: 'Elastic Learned Sparse EncodeR v2 (Tech Preview)', + name: '.elser_model_2', + }) + ), + } as unknown as jest.Mocked, }; }; diff --git a/x-pack/plugins/ml/public/plugin.ts b/x-pack/plugins/ml/public/plugin.ts index 3a32f8b25ae89..4eae00a53d401 100644 --- a/x-pack/plugins/ml/public/plugin.ts +++ b/x-pack/plugins/ml/public/plugin.ts @@ -48,6 +48,10 @@ import type { ChartsPluginStart } from '@kbn/charts-plugin/public'; import type { CasesUiSetup, CasesUiStart } from '@kbn/cases-plugin/public'; import type { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public'; import type { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public'; +import { + getMlSharedServices, + MlSharedServices, +} from './application/services/get_shared_ml_services'; import { registerManagementSection } from './application/management'; import { MlLocatorDefinition, type MlLocator } from './locator'; import { setDependencyCache } from './application/util/dependency_cache'; @@ -103,6 +107,9 @@ export class MlPlugin implements Plugin { private appUpdater$ = new BehaviorSubject(() => ({})); private locator: undefined | MlLocator; + + private sharedMlServices: MlSharedServices | undefined; + private isServerless: boolean = false; constructor(private initializerContext: PluginInitializerContext) { @@ -110,6 +117,8 @@ export class MlPlugin implements Plugin { } setup(core: MlCoreSetup, pluginsSetup: MlSetupDependencies) { + this.sharedMlServices = getMlSharedServices(core.http); + core.application.register({ id: PLUGIN_ID, title: i18n.translate('xpack.ml.plugin.title', { @@ -249,6 +258,7 @@ export class MlPlugin implements Plugin { return { locator: this.locator, + elasticModels: this.sharedMlServices?.elasticModels, }; } diff --git a/x-pack/plugins/ml/scripts/apidoc_scripts/apidoc_config/apidoc.json b/x-pack/plugins/ml/scripts/apidoc_scripts/apidoc_config/apidoc.json index 6ec23bc13c559..a6e647a60fe9f 100644 --- a/x-pack/plugins/ml/scripts/apidoc_scripts/apidoc_config/apidoc.json +++ b/x-pack/plugins/ml/scripts/apidoc_scripts/apidoc_config/apidoc.json @@ -180,6 +180,8 @@ "InferTrainedModelDeployment", "CreateInferencePipeline", "GetIngestPipelines", + "GetTrainedModelDownloadList", + "GetElserConfig", "Alerting", "PreviewAlert", diff --git a/x-pack/plugins/ml/server/models/model_management/model_provider.test.ts b/x-pack/plugins/ml/server/models/model_management/model_provider.test.ts new file mode 100644 index 0000000000000..7e66d03033b66 --- /dev/null +++ b/x-pack/plugins/ml/server/models/model_management/model_provider.test.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 { modelsProvider } from './models_provider'; +import { type IScopedClusterClient } from '@kbn/core/server'; +import { cloudMock } from '@kbn/cloud-plugin/server/mocks'; + +describe('modelsProvider', () => { + const mockClient = { + asInternalUser: { + transport: { + request: jest.fn().mockResolvedValue({ + _nodes: { + total: 1, + successful: 1, + failed: 0, + }, + cluster_name: 'default', + nodes: { + yYmqBqjpQG2rXsmMSPb9pQ: { + name: 'node-0', + roles: ['ml'], + attributes: {}, + os: { + name: 'Linux', + arch: 'amd64', + }, + }, + }, + }), + }, + }, + } as unknown as jest.Mocked; + + const mockCloud = cloudMock.createSetup(); + const modelService = modelsProvider(mockClient, mockCloud); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('getELSER', () => { + test('provides a recommended definition by default', async () => { + const result = await modelService.getELSER(); + expect(result.name).toEqual('.elser_model_2_linux-x86_64_SNAPSHOT'); + }); + + test('provides a default version if there is no recommended', async () => { + mockCloud.cloudId = undefined; + (mockClient.asInternalUser.transport.request as jest.Mock).mockResolvedValueOnce({ + _nodes: { + total: 1, + successful: 1, + failed: 0, + }, + cluster_name: 'default', + nodes: { + yYmqBqjpQG2rXsmMSPb9pQ: { + name: 'node-0', + roles: ['ml'], + attributes: {}, + os: { + name: 'Mac OS X', + arch: 'aarch64', + }, + }, + }, + }); + + const result = await modelService.getELSER(); + expect(result.name).toEqual('.elser_model_2_SNAPSHOT'); + }); + + test('provides the requested version', async () => { + const result = await modelService.getELSER({ version: 1 }); + expect(result.name).toEqual('.elser_model_1'); + }); + + test('provides the requested version of a recommended architecture', async () => { + const result = await modelService.getELSER({ version: 2 }); + expect(result.name).toEqual('.elser_model_2_linux-x86_64_SNAPSHOT'); + }); + }); +}); diff --git a/x-pack/plugins/ml/server/models/model_management/models_provider.ts b/x-pack/plugins/ml/server/models/model_management/models_provider.ts index e7cfcbe7fd50d..f6164ad6e65ca 100644 --- a/x-pack/plugins/ml/server/models/model_management/models_provider.ts +++ b/x-pack/plugins/ml/server/models/model_management/models_provider.ts @@ -6,16 +6,23 @@ */ import type { IScopedClusterClient } from '@kbn/core/server'; -import { +import type { IngestPipeline, IngestSimulateDocument, IngestSimulateRequest, + NodesInfoResponseBase, } from '@elastic/elasticsearch/lib/api/types'; +import { + ELASTIC_MODEL_DEFINITIONS, + type GetElserOptions, + type ModelDefinitionResponse, +} from '@kbn/ml-trained-models-utils'; +import type { CloudSetup } from '@kbn/cloud-plugin/server'; import type { PipelineDefinition } from '../../../common/types/trained_models'; export type ModelService = ReturnType; -export function modelsProvider(client: IScopedClusterClient) { +export function modelsProvider(client: IScopedClusterClient, cloud?: CloudSetup) { return { /** * Retrieves the map of model ids and aliases with associated pipelines. @@ -128,5 +135,83 @@ export function modelsProvider(client: IScopedClusterClient) { return result; }, + + /** + * Returns a list of elastic curated models available for download. + */ + async getModelDownloads(): Promise { + // We assume that ML nodes in Cloud are always on linux-x86_64, even if other node types aren't. + const isCloud = !!cloud?.cloudId; + + const nodesInfoResponse = + await client.asInternalUser.transport.request({ + method: 'GET', + path: `/_nodes/ml:true/os`, + }); + + let osName: string | undefined; + let arch: string | undefined; + // Indicates that all ML nodes have the same architecture + let sameArch = true; + for (const node of Object.values(nodesInfoResponse.nodes)) { + if (!osName) { + osName = node.os?.name; + } + if (!arch) { + arch = node.os?.arch; + } + if (node.os?.name !== osName || node.os?.arch !== arch) { + sameArch = false; + break; + } + } + + const result = Object.entries(ELASTIC_MODEL_DEFINITIONS).map(([name, def]) => { + const recommended = + (isCloud && def.os === 'Linux' && def.arch === 'amd64') || + (sameArch && !!def?.os && def?.os === osName && def?.arch === arch); + return { + ...def, + name, + ...(recommended ? { recommended } : {}), + }; + }); + + return result; + }, + + /** + * Provides an ELSER model name and configuration for download based on the current cluster architecture. + * The current default version is 2. If running on Cloud it returns the Linux x86_64 optimized version. + * If any of the ML nodes run a different OS rather than Linux, or the CPU architecture isn't x86_64, + * a portable version of the model is returned. + */ + async getELSER(options?: GetElserOptions): Promise | never { + const modelDownloadConfig = await this.getModelDownloads(); + + let requestedModel: ModelDefinitionResponse | undefined; + let recommendedModel: ModelDefinitionResponse | undefined; + let defaultModel: ModelDefinitionResponse | undefined; + + for (const model of modelDownloadConfig) { + if (options?.version === model.version) { + requestedModel = model; + if (model.recommended) { + requestedModel = model; + break; + } + } else if (model.recommended) { + recommendedModel = model; + } else if (model.default) { + defaultModel = model; + } + } + + if (!requestedModel && !defaultModel && !recommendedModel) { + throw new Error('Requested model not found'); + } + + return requestedModel || recommendedModel || defaultModel!; + }, }; } diff --git a/x-pack/plugins/ml/server/plugin.ts b/x-pack/plugins/ml/server/plugin.ts index 342350fac998a..dcd97acabcbd8 100644 --- a/x-pack/plugins/ml/server/plugin.ts +++ b/x-pack/plugins/ml/server/plugin.ts @@ -241,7 +241,7 @@ export class MlServerPlugin // Register Trained Model Management routes if (this.enabledFeatures.dfa || this.enabledFeatures.nlp) { modelManagementRoutes(routeInit); - trainedModelsRoutes(routeInit); + trainedModelsRoutes(routeInit, plugins.cloud); } // Register Miscellaneous routes diff --git a/x-pack/plugins/ml/server/routes/schemas/inference_schema.ts b/x-pack/plugins/ml/server/routes/schemas/inference_schema.ts index 21b62c6f5ce42..1b48a49c8d82f 100644 --- a/x-pack/plugins/ml/server/routes/schemas/inference_schema.ts +++ b/x-pack/plugins/ml/server/routes/schemas/inference_schema.ts @@ -87,3 +87,7 @@ export const createIngestPipelineSchema = schema.object({ }) ), }); + +export const modelDownloadsQuery = schema.object({ + version: schema.maybe(schema.oneOf([schema.literal('1'), schema.literal('2')])), +}); diff --git a/x-pack/plugins/ml/server/routes/trained_models.ts b/x-pack/plugins/ml/server/routes/trained_models.ts index ab5d3a87e8f46..8685652ab3189 100644 --- a/x-pack/plugins/ml/server/routes/trained_models.ts +++ b/x-pack/plugins/ml/server/routes/trained_models.ts @@ -9,6 +9,8 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { schema } from '@kbn/config-schema'; import type { ErrorType } from '@kbn/ml-error-utils'; import type { MlGetTrainedModelsRequest } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { type ElserVersion } from '@kbn/ml-trained-models-utils'; +import type { CloudSetup } from '@kbn/cloud-plugin/server'; import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app'; import type { MlFeatures, RouteInitialization } from '../types'; import { wrapError } from '../client/error_wrapper'; @@ -25,6 +27,7 @@ import { threadingParamsSchema, updateDeploymentParamsSchema, createIngestPipelineSchema, + modelDownloadsQuery, } from './schemas/inference_schema'; import type { TrainedModelConfigResponse } from '../../common/types/trained_models'; import { mlLog } from '../lib/log'; @@ -49,11 +52,10 @@ export function filterForEnabledFeatureModels( return filteredModels; } -export function trainedModelsRoutes({ - router, - routeGuard, - getEnabledFeatures, -}: RouteInitialization) { +export function trainedModelsRoutes( + { router, routeGuard, getEnabledFeatures }: RouteInitialization, + cloud: CloudSetup +) { /** * @apiGroup TrainedModels * @@ -652,4 +654,78 @@ export function trainedModelsRoutes({ } }) ); + + /** + * @apiGroup TrainedModels + * + * @api {get} /internal/ml/trained_models/model_downloads Gets available models for download + * @apiName GetTrainedModelDownloadList + * @apiDescription Gets available models for download with default and recommended flags based on the cluster OS and CPU architecture. + */ + router.versioned + .get({ + path: `${ML_INTERNAL_BASE_PATH}/trained_models/model_downloads`, + access: 'internal', + options: { + tags: ['access:ml:canGetTrainedModels'], + }, + }) + .addVersion( + { + version: '1', + validate: false, + }, + routeGuard.fullLicenseAPIGuard(async ({ response, client }) => { + try { + const body = await modelsProvider(client, cloud).getModelDownloads(); + + return response.ok({ + body, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup TrainedModels + * + * @api {get} /internal/ml/trained_models/elser_config Gets ELSER config for download + * @apiName GetElserConfig + * @apiDescription Gets ELSER config for download based on the cluster OS and CPU architecture. + */ + router.versioned + .get({ + path: `${ML_INTERNAL_BASE_PATH}/trained_models/elser_config`, + access: 'internal', + options: { + tags: ['access:ml:canGetTrainedModels'], + }, + }) + .addVersion( + { + version: '1', + validate: { + request: { + query: modelDownloadsQuery, + }, + }, + }, + routeGuard.fullLicenseAPIGuard(async ({ response, client, request }) => { + try { + const { version } = request.query; + + const body = await modelsProvider(client, cloud).getELSER( + version ? { version: Number(version) as ElserVersion } : undefined + ); + + return response.ok({ + body, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); } diff --git a/x-pack/plugins/ml/server/shared_services/providers/trained_models.ts b/x-pack/plugins/ml/server/shared_services/providers/trained_models.ts index c2b3f41551afd..b884edd99c22d 100644 --- a/x-pack/plugins/ml/server/shared_services/providers/trained_models.ts +++ b/x-pack/plugins/ml/server/shared_services/providers/trained_models.ts @@ -6,13 +6,16 @@ */ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { CloudSetup } from '@kbn/cloud-plugin/server'; import type { KibanaRequest, SavedObjectsClientContract } from '@kbn/core/server'; +import type { GetElserOptions } from '@kbn/ml-trained-models-utils'; import type { MlInferTrainedModelRequest, MlStopTrainedModelDeploymentRequest, UpdateTrainedModelDeploymentRequest, UpdateTrainedModelDeploymentResponse, } from '../../lib/ml_client/types'; +import { modelsProvider } from '../../models/model_management'; import type { GetGuards } from '../shared_services'; export interface TrainedModelsProvider { @@ -47,7 +50,10 @@ export interface TrainedModelsProvider { }; } -export function getTrainedModelsProvider(getGuards: GetGuards): TrainedModelsProvider { +export function getTrainedModelsProvider( + getGuards: GetGuards, + cloud: CloudSetup +): TrainedModelsProvider { return { trainedModelsProvider(request: KibanaRequest, savedObjectsClient: SavedObjectsClientContract) { const guards = getGuards(request, savedObjectsClient); @@ -116,6 +122,14 @@ export function getTrainedModelsProvider(getGuards: GetGuards): TrainedModelsPro return mlClient.putTrainedModel(params); }); }, + async getELSER(params: GetElserOptions) { + return await guards + .isFullLicense() + .hasMlCapabilities(['canGetTrainedModels']) + .ok(async ({ scopedClient }) => { + return modelsProvider(scopedClient, cloud).getELSER(params); + }); + }, }; }, }; diff --git a/x-pack/plugins/ml/server/shared_services/shared_services.ts b/x-pack/plugins/ml/server/shared_services/shared_services.ts index 752820f57cf2a..235a30f541984 100644 --- a/x-pack/plugins/ml/server/shared_services/shared_services.ts +++ b/x-pack/plugins/ml/server/shared_services/shared_services.ts @@ -186,7 +186,7 @@ export function createSharedServices( ...getResultsServiceProvider(getGuards), ...getMlSystemProvider(getGuards, mlLicense, getSpaces, cloud, resolveMlCapabilities), ...getAlertingServiceProvider(getGuards), - ...getTrainedModelsProvider(getGuards), + ...getTrainedModelsProvider(getGuards, cloud), }, /** * Services providers for ML internal usage diff --git a/x-pack/plugins/ml/tsconfig.json b/x-pack/plugins/ml/tsconfig.json index 57811ff1201fe..2532a6b7824ee 100644 --- a/x-pack/plugins/ml/tsconfig.json +++ b/x-pack/plugins/ml/tsconfig.json @@ -104,5 +104,6 @@ "@kbn/ml-in-memory-table", "@kbn/presentation-util-plugin", "@kbn/react-kibana-mount", + "@kbn/core-http-browser", ], } From 88fdebdc8114394f0f87758187292003c6548007 Mon Sep 17 00:00:00 2001 From: Kevin Lacabane Date: Mon, 25 Sep 2023 18:28:09 +0200 Subject: [PATCH 19/45] [apm] allow retrieval of metric indices (#167041) ### Summary Closes https://github.com/elastic/kibana/issues/166961 `/internal/apm/services/{serviceName}/infrastructure_attributes` route was disabled in serverless as it relied on an infra API to function. Since the infra plugin dependency was removed in https://github.com/elastic/kibana/pull/164094 we can reenable the route ### Testing I used a ccs cluster connected to edge-oblt and had to update the apm indices to also search the remote_cluster ``` xpack.apm.indices.metric: remote_cluster:metrics-apm*,remote_cluster:apm*,metrics-apm*,apm* xpack.apm.indices.transaction: remote_cluster:traces-apm*,remote_cluster:apm*,traces-apm*,apm* xpack.apm.indices.span: remote_cluster:traces-apm*,remote_cluster:apm*,traces-apm*,apm* xpack.apm.indices.error: remote_cluster:logs-apm*,remote_cluster:apm*,logs-apm*,apm* ``` - start serverless kibana - navigate to Applications -> Services, we need to select a [service linked to a container](https://github.com/elastic/kibana/blob/main/x-pack/plugins/apm/server/routes/infrastructure/get_host_names.ts#L23) to fully trigger the route logic (you can pick `quoteservice` if connected to edge-oblt data) - navigate to Logs tab - call to `/infrastructure_attributes` is successful --- .../create_infra_metrics_client.ts | 2 +- .../lib/helpers/get_infra_metric_indices.ts | 25 ------------------- .../apm/server/routes/infrastructure/route.ts | 5 ---- .../apm/server/routes/services/route.ts | 7 ++---- .../server/client/client.test.ts | 25 +++++++++++++------ .../server/client/client.ts | 8 +++--- 6 files changed, 24 insertions(+), 48 deletions(-) delete mode 100644 x-pack/plugins/apm/server/lib/helpers/get_infra_metric_indices.ts diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_infra_metrics_client/create_infra_metrics_client.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_infra_metrics_client/create_infra_metrics_client.ts index f7ae6ea53147a..eff505b22bd4a 100644 --- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_infra_metrics_client/create_infra_metrics_client.ts +++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_infra_metrics_client/create_infra_metrics_client.ts @@ -6,7 +6,7 @@ */ import { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; -import { APMRouteHandlerResources } from '../../../../routes/typings'; +import { APMRouteHandlerResources } from '../../../../routes/apm_routes/register_apm_server_routes'; type InfraMetricsSearchParams = Omit & { size: number; diff --git a/x-pack/plugins/apm/server/lib/helpers/get_infra_metric_indices.ts b/x-pack/plugins/apm/server/lib/helpers/get_infra_metric_indices.ts deleted file mode 100644 index 24b76edb4d887..0000000000000 --- a/x-pack/plugins/apm/server/lib/helpers/get_infra_metric_indices.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { SavedObjectsClientContract } from '@kbn/core/server'; -import { APMRouteHandlerResources } from '../../routes/apm_routes/register_apm_server_routes'; - -export async function getInfraMetricIndices({ - infraPlugin, - savedObjectsClient, -}: { - infraPlugin: Required; - savedObjectsClient: SavedObjectsClientContract; -}): Promise { - if (!infraPlugin) { - throw new Error('Infra Plugin needs to be setup'); - } - const infra = await infraPlugin.start(); - const infraMetricIndices = await infra.getMetricIndices(savedObjectsClient); - - return infraMetricIndices; -} diff --git a/x-pack/plugins/apm/server/routes/infrastructure/route.ts b/x-pack/plugins/apm/server/routes/infrastructure/route.ts index 4117a43ce1e3f..9050f1a46622c 100644 --- a/x-pack/plugins/apm/server/routes/infrastructure/route.ts +++ b/x-pack/plugins/apm/server/routes/infrastructure/route.ts @@ -5,7 +5,6 @@ * 2.0. */ import * as t from 'io-ts'; -import Boom from '@hapi/boom'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; import { environmentRt, kueryRt, rangeRt } from '../default_api_types'; @@ -30,10 +29,6 @@ const infrastructureRoute = createApmServerRoute({ hostNames: string[]; podNames: string[]; }> => { - if (!resources.plugins.infra) { - throw Boom.notFound(); - } - const apmEventClient = await getApmEventClient(resources); const infraMetricsClient = createInfraMetricsClient(resources); const { params } = resources; diff --git a/x-pack/plugins/apm/server/routes/services/route.ts b/x-pack/plugins/apm/server/routes/services/route.ts index 4ac0a37b3d10d..970a72d478f72 100644 --- a/x-pack/plugins/apm/server/routes/services/route.ts +++ b/x-pack/plugins/apm/server/routes/services/route.ts @@ -250,7 +250,7 @@ const serviceMetadataDetailsRoute = createApmServerRoute({ end, }); - if (serviceMetadataDetails?.container?.ids && resources.plugins.infra) { + if (serviceMetadataDetails?.container?.ids) { const infraMetricsClient = createInfraMetricsClient(resources); const containerMetadata = await getServiceOverviewContainerMetadata({ infraMetricsClient, @@ -761,10 +761,7 @@ export const serviceInstancesMetadataDetails = createApmServerRoute({ end, }); - if ( - serviceInstanceMetadataDetails?.container?.id && - resources.plugins.infra - ) { + if (serviceInstanceMetadataDetails?.container?.id) { const infraMetricsClient = createInfraMetricsClient(resources); const containerMetadata = await getServiceInstanceContainerMetadata({ infraMetricsClient, diff --git a/x-pack/plugins/metrics_data_access/server/client/client.test.ts b/x-pack/plugins/metrics_data_access/server/client/client.test.ts index 72449cf47132b..d96d8efecf52f 100644 --- a/x-pack/plugins/metrics_data_access/server/client/client.test.ts +++ b/x-pack/plugins/metrics_data_access/server/client/client.test.ts @@ -7,18 +7,13 @@ import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; -import { MetricsDataClient } from './client'; +import { MetricsDataClient, DEFAULT_METRIC_INDICES } from './client'; import { metricsDataSourceSavedObjectName } from '../saved_objects/metrics_data_source'; describe('MetricsDataClient', () => { - const client = new MetricsDataClient(); - - client.setDefaultMetricIndicesHandler(async () => { - return 'fallback-indices*'; - }); - describe('metric indices', () => { it('retrieves metrics saved object', async () => { + const client = new MetricsDataClient(); const savedObjectsClient = { get: jest.fn().mockResolvedValue({ attributes: { metricIndices: 'foo,bar' } }), }; @@ -36,6 +31,10 @@ describe('MetricsDataClient', () => { }); it('falls back to provided handler when no metrics saved object exists', async () => { + const client = new MetricsDataClient(); + client.setDefaultMetricIndicesHandler(async () => { + return 'fallback-indices*'; + }); const savedObjectsClient = { get: jest.fn().mockRejectedValue(SavedObjectsErrorHelpers.createGenericNotFoundError()), }; @@ -51,5 +50,17 @@ describe('MetricsDataClient', () => { ]); expect(indices).toEqual('fallback-indices*'); }); + + it('falls back to static indices when no fallback exists', async () => { + const client = new MetricsDataClient(); + const savedObjectsClient = { + get: jest.fn().mockRejectedValue(SavedObjectsErrorHelpers.createGenericNotFoundError()), + }; + + const indices = await client.getMetricIndices({ + savedObjectsClient: savedObjectsClient as unknown as SavedObjectsClientContract, + }); + expect(indices).toEqual(DEFAULT_METRIC_INDICES); + }); }); }); diff --git a/x-pack/plugins/metrics_data_access/server/client/client.ts b/x-pack/plugins/metrics_data_access/server/client/client.ts index 30d367cea0293..26359cae578a7 100644 --- a/x-pack/plugins/metrics_data_access/server/client/client.ts +++ b/x-pack/plugins/metrics_data_access/server/client/client.ts @@ -16,21 +16,19 @@ import { metricsDataSourceSavedObjectName, } from '../saved_objects/metrics_data_source'; +export const DEFAULT_METRIC_INDICES = 'metrics-*,metricbeat-*'; + export class MetricsDataClient { private readonly defaultSavedObjectId = 'default'; private getDefaultMetricIndices: DefaultMetricIndicesHandler = null; async getMetricIndices(options: GetMetricIndicesOptions): Promise { - if (!this.getDefaultMetricIndices) { - throw new Error('Missing getMetricsIndices fallback'); - } - const metricIndices = await options.savedObjectsClient .get(metricsDataSourceSavedObjectName, this.defaultSavedObjectId) .then(({ attributes }) => attributes.metricIndices) .catch((err) => { if (SavedObjectsErrorHelpers.isNotFoundError(err)) { - return this.getDefaultMetricIndices!(options); + return this.getDefaultMetricIndices?.(options) ?? DEFAULT_METRIC_INDICES; } throw err; From 8c853b6ca77735b17db4b4f384e5d426189a755b Mon Sep 17 00:00:00 2001 From: Paulo Henrique Date: Mon, 25 Sep 2023 09:32:12 -0700 Subject: [PATCH 20/45] [Cloud Security] [CSPM] Update cloud native deployment instructions (#166419) --- .../aws_credentials_form/aws_credentials_form.tsx | 6 ++++++ .../components/fleet_extensions/gcp_credential_form.tsx | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx index b1774547a6e6d..fdc7d8c0f328f 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx @@ -133,6 +133,12 @@ const CloudFormationSetup = ({ list-style: auto; `} > +
  • + +
  • {accountType === AWS_ORGANIZATION_ACCOUNT ? (
  • { list-style: auto; `} > +
  • + +
  • Date: Mon, 25 Sep 2023 09:32:53 -0700 Subject: [PATCH 21/45] [Cloud Security] [Dashboard Navigation] Fix edit filter when navigating from dashboard (#166500) --- .../common/constants.ts | 2 + .../hooks/use_navigate_findings.test.ts | 40 ++++++++++++++++--- .../common/hooks/use_navigate_findings.ts | 27 +++++++++---- 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/common/constants.ts b/x-pack/plugins/cloud_security_posture/common/constants.ts index e1bcdc1f9a95f..7f0b4f62fb216 100644 --- a/x-pack/plugins/cloud_security_posture/common/constants.ts +++ b/x-pack/plugins/cloud_security_posture/common/constants.ts @@ -65,6 +65,8 @@ export const LATEST_VULNERABILITIES_RETENTION_POLICY = '3d'; export const DATA_VIEW_INDEX_PATTERN = 'logs-*'; +export const SECURITY_DEFAULT_DATA_VIEW_ID = 'security-solution-default'; + export const CSP_INGEST_TIMESTAMP_PIPELINE = 'cloud_security_posture_add_ingest_timestamp_pipeline'; export const CSP_LATEST_FINDINGS_INGEST_TIMESTAMP_PIPELINE = 'cloud_security_posture_latest_index_add_ingest_timestamp_pipeline'; diff --git a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.test.ts b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.test.ts index 9bdd3bfada098..e3d213118dd51 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.test.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.test.ts @@ -6,7 +6,11 @@ */ import { renderHook, act } from '@testing-library/react-hooks/dom'; -import { useNavigateFindings, useNavigateFindingsByResource } from './use_navigate_findings'; +import { + useNavigateFindings, + useNavigateFindingsByResource, + useNavigateVulnerabilities, +} from './use_navigate_findings'; import { useHistory } from 'react-router-dom'; jest.mock('react-router-dom', () => ({ @@ -29,9 +33,17 @@ jest.mock('./use_kibana', () => ({ }, }), })); +jest.mock('../api/use_latest_findings_data_view', () => ({ + useLatestFindingsDataView: jest.fn().mockReturnValue({ + status: 'success', + data: { + id: 'data-view-id', + }, + }), +})); describe('useNavigateFindings', () => { - it('creates a URL to findings page with correct path and filter', () => { + it('creates a URL to findings page with correct path, filter and dataViewId', () => { const push = jest.fn(); (useHistory as jest.Mock).mockReturnValueOnce({ push }); @@ -44,7 +56,7 @@ describe('useNavigateFindings', () => { expect(push).toHaveBeenCalledWith({ pathname: '/cloud_security_posture/findings/configurations', search: - "cspq=(filters:!((meta:(alias:!n,disabled:!f,key:foo,negate:!f,type:phrase),query:(match_phrase:(foo:1)))),query:(language:kuery,query:''))", + "cspq=(filters:!((meta:(alias:!n,disabled:!f,index:data-view-id,key:foo,negate:!f,type:phrase),query:(match_phrase:(foo:1)))),query:(language:kuery,query:''))", }); expect(push).toHaveBeenCalledTimes(1); }); @@ -62,7 +74,7 @@ describe('useNavigateFindings', () => { expect(push).toHaveBeenCalledWith({ pathname: '/cloud_security_posture/findings/configurations', search: - "cspq=(filters:!((meta:(alias:!n,disabled:!f,key:foo,negate:!t,type:phrase),query:(match_phrase:(foo:1)))),query:(language:kuery,query:''))", + "cspq=(filters:!((meta:(alias:!n,disabled:!f,index:data-view-id,key:foo,negate:!t,type:phrase),query:(match_phrase:(foo:1)))),query:(language:kuery,query:''))", }); expect(push).toHaveBeenCalledTimes(1); }); @@ -80,7 +92,25 @@ describe('useNavigateFindings', () => { expect(push).toHaveBeenCalledWith({ pathname: '/cloud_security_posture/findings/resource', search: - "cspq=(filters:!((meta:(alias:!n,disabled:!f,key:foo,negate:!f,type:phrase),query:(match_phrase:(foo:1)))),query:(language:kuery,query:''))", + "cspq=(filters:!((meta:(alias:!n,disabled:!f,index:data-view-id,key:foo,negate:!f,type:phrase),query:(match_phrase:(foo:1)))),query:(language:kuery,query:''))", + }); + expect(push).toHaveBeenCalledTimes(1); + }); + + it('creates a URL to vulnerabilities page with correct path, filter and dataViewId', () => { + const push = jest.fn(); + (useHistory as jest.Mock).mockReturnValueOnce({ push }); + + const { result } = renderHook(() => useNavigateVulnerabilities()); + + act(() => { + result.current({ foo: 1 }); + }); + + expect(push).toHaveBeenCalledWith({ + pathname: '/cloud_security_posture/findings/vulnerabilities', + search: + "cspq=(filters:!((meta:(alias:!n,disabled:!f,index:security-solution-default,key:foo,negate:!f,type:phrase),query:(match_phrase:(foo:1)))),query:(language:kuery,query:''))", }); expect(push).toHaveBeenCalledTimes(1); }); diff --git a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.ts b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.ts index 48b16f62cbaf5..fbeeeb32a0c2e 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.ts @@ -8,9 +8,14 @@ import { useCallback } from 'react'; import { useHistory } from 'react-router-dom'; import { Filter } from '@kbn/es-query'; +import { + LATEST_FINDINGS_INDEX_PATTERN, + SECURITY_DEFAULT_DATA_VIEW_ID, +} from '../../../common/constants'; import { findingsNavigation } from '../navigation/constants'; import { encodeQuery } from '../navigation/query_utils'; import { useKibana } from './use_kibana'; +import { useLatestFindingsDataView } from '../api/use_latest_findings_data_view'; interface NegatedValue { value: string | number; @@ -21,7 +26,7 @@ type FilterValue = string | number | NegatedValue; export type NavFilter = Record; -const createFilter = (key: string, filterValue: FilterValue): Filter => { +const createFilter = (key: string, filterValue: FilterValue, dataViewId: string): Filter => { let negate = false; let value = filterValue; if (typeof filterValue === 'object') { @@ -32,7 +37,7 @@ const createFilter = (key: string, filterValue: FilterValue): Filter => { if (value === '*') { return { query: { exists: { field: key } }, - meta: { type: 'exists' }, + meta: { type: 'exists', index: dataViewId }, }; } return { @@ -42,18 +47,19 @@ const createFilter = (key: string, filterValue: FilterValue): Filter => { disabled: false, type: 'phrase', key, + index: dataViewId, }, query: { match_phrase: { [key]: value } }, }; }; -const useNavigate = (pathname: string) => { +const useNavigate = (pathname: string, dataViewId = SECURITY_DEFAULT_DATA_VIEW_ID) => { const history = useHistory(); const { services } = useKibana(); return useCallback( (filterParams: NavFilter = {}) => { const filters = Object.entries(filterParams).map(([key, filterValue]) => - createFilter(key, filterValue) + createFilter(key, filterValue, dataViewId) ); history.push({ @@ -65,14 +71,19 @@ const useNavigate = (pathname: string) => { }), }); }, - [pathname, history, services.data.query.queryString] + [pathname, history, services.data.query.queryString, dataViewId] ); }; -export const useNavigateFindings = () => useNavigate(findingsNavigation.findings_default.path); +export const useNavigateFindings = () => { + const { data } = useLatestFindingsDataView(LATEST_FINDINGS_INDEX_PATTERN); + return useNavigate(findingsNavigation.findings_default.path, data?.id); +}; -export const useNavigateFindingsByResource = () => - useNavigate(findingsNavigation.findings_by_resource.path); +export const useNavigateFindingsByResource = () => { + const { data } = useLatestFindingsDataView(LATEST_FINDINGS_INDEX_PATTERN); + return useNavigate(findingsNavigation.findings_by_resource.path, data?.id); +}; export const useNavigateVulnerabilities = () => useNavigate(findingsNavigation.vulnerabilities.path); From 778dbf26b9bcd5b43e53a41b1646974dfe9352ea Mon Sep 17 00:00:00 2001 From: Paulo Henrique Date: Mon, 25 Sep 2023 09:33:13 -0700 Subject: [PATCH 22/45] [Cloud Security] [Misconfigurations] Test coverage for the Alerts workflow (#166788) --- .../detection_rule_counter.test.tsx | 138 ++++++++++ .../components/detection_rule_counter.tsx | 24 +- .../public/components/take_action.tsx | 9 +- .../page_objects/findings_page.ts | 70 +++++- .../pages/findings_alerts.ts | 236 ++++++++++++++++++ .../pages/index.ts | 1 + 6 files changed, 468 insertions(+), 10 deletions(-) create mode 100644 x-pack/plugins/cloud_security_posture/public/components/detection_rule_counter.test.tsx create mode 100644 x-pack/test/cloud_security_posture_functional/pages/findings_alerts.ts diff --git a/x-pack/plugins/cloud_security_posture/public/components/detection_rule_counter.test.tsx b/x-pack/plugins/cloud_security_posture/public/components/detection_rule_counter.test.tsx new file mode 100644 index 0000000000000..1e2f2f52fd02a --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/detection_rule_counter.test.tsx @@ -0,0 +1,138 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { render, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { DetectionRuleCounter } from './detection_rule_counter'; +import { TestProvider } from '../test/test_provider'; +import { useFetchDetectionRulesByTags } from '../common/api/use_fetch_detection_rules_by_tags'; +import { useFetchDetectionRulesAlertsStatus } from '../common/api/use_fetch_detection_rules_alerts_status'; +import { RuleResponse } from '../common/types'; + +jest.mock('../common/api/use_fetch_detection_rules_by_tags', () => ({ + useFetchDetectionRulesByTags: jest.fn(), +})); +jest.mock('../common/api/use_fetch_detection_rules_alerts_status', () => ({ + useFetchDetectionRulesAlertsStatus: jest.fn(), +})); + +describe('DetectionRuleCounter', () => { + beforeEach(() => { + jest.restoreAllMocks(); + }); + it('should render loading skeleton when both rules and alerts are loading', () => { + (useFetchDetectionRulesByTags as jest.Mock).mockReturnValue({ + data: undefined, + isLoading: true, + }); + + (useFetchDetectionRulesAlertsStatus as jest.Mock).mockReturnValue({ + data: undefined, + isLoading: true, + }); + const { getByTestId } = render( + + + + ); + + const skeletonText = getByTestId('csp:detection-rule-counter-loading'); + expect(skeletonText).toBeInTheDocument(); + }); + + it('should render create rule link when no rules exist', () => { + (useFetchDetectionRulesByTags as jest.Mock).mockReturnValue({ + data: { total: 0 }, + isLoading: false, + }); + + (useFetchDetectionRulesAlertsStatus as jest.Mock).mockReturnValue({ + data: null, + isLoading: false, + isFetching: false, + }); + + const { getByText, getByTestId } = render( + + + + ); + + const createRuleLink = getByTestId('csp:findings-flyout-create-detection-rule-link'); + expect(createRuleLink).toBeInTheDocument(); + expect(getByText('Create a detection rule')).toBeInTheDocument(); + }); + + it('should render alert and rule count when rules exist', () => { + (useFetchDetectionRulesByTags as jest.Mock).mockReturnValue({ + data: { total: 5 }, + isLoading: false, + }); + + (useFetchDetectionRulesAlertsStatus as jest.Mock).mockReturnValue({ + data: { total: 10 }, + isLoading: false, + isFetching: false, + }); + + const { getByText, getByTestId } = render( + + + + ); + + const alertCountLink = getByTestId('csp:findings-flyout-alert-count'); + const ruleCountLink = getByTestId('csp:findings-flyout-detection-rule-count'); + + expect(alertCountLink).toBeInTheDocument(); + expect(getByText(/10 alerts/i)).toBeInTheDocument(); + expect(ruleCountLink).toBeInTheDocument(); + expect(getByText(/5 detection rules/i)).toBeInTheDocument(); + }); + + it('should show loading spinner when creating a rule', async () => { + (useFetchDetectionRulesByTags as jest.Mock).mockReturnValue({ + data: { total: 0 }, + isLoading: false, + }); + + (useFetchDetectionRulesAlertsStatus as jest.Mock).mockReturnValue({ + data: null, + isLoading: false, + isFetching: false, + }); + const createRuleFn = jest.fn(() => Promise.resolve({} as RuleResponse)); + const { getByTestId, queryByTestId } = render( + + + + ); + + // Trigger createDetectionRuleOnClick + const createRuleLink = getByTestId('csp:findings-flyout-create-detection-rule-link'); + userEvent.click(createRuleLink); + + const loadingSpinner = getByTestId('csp:findings-flyout-detection-rule-counter-loading'); + expect(loadingSpinner).toBeInTheDocument(); + + (useFetchDetectionRulesByTags as jest.Mock).mockReturnValue({ + data: { total: 1 }, + isLoading: false, + }); + + (useFetchDetectionRulesAlertsStatus as jest.Mock).mockReturnValue({ + data: { total: 0 }, + isLoading: false, + isFetching: false, + }); + + // Wait for the loading spinner to disappear + await waitFor(() => { + expect(queryByTestId('csp:findings-flyout-detection-rule-counter-loading')).toBeNull(); + }); + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/public/components/detection_rule_counter.tsx b/x-pack/plugins/cloud_security_posture/public/components/detection_rule_counter.tsx index eeea89f9a310f..b2a79710d09a2 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/detection_rule_counter.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/detection_rule_counter.tsx @@ -68,7 +68,12 @@ export const DetectionRuleCounter = ({ tags, createRuleFn }: DetectionRuleCounte }, [createRuleFn, http, notifications, queryClient]); return ( - + {rulesData?.total === 0 ? ( <> @@ -78,11 +83,17 @@ export const DetectionRuleCounter = ({ tags, createRuleFn }: DetectionRuleCounte id="xpack.csp.findingsFlyout.alerts.creatingRule" defaultMessage="Creating detection rule" />{' '} - + ) : ( <> - + ) : ( <> - + {' '} - + - {ruleResponse.name} + {ruleResponse.name} {` `} - + (findingsMock: T[]) => { + add: async < + T extends { + '@timestamp'?: string; + } + >( + findingsMock: T[] + ) => { await Promise.all([ ...findingsMock.map((finding) => es.index({ index: FINDINGS_INDEX, body: { ...finding, - '@timestamp': new Date().toISOString(), + '@timestamp': finding['@timestamp'] ?? new Date().toISOString(), }, refresh: true, }) @@ -72,7 +78,7 @@ export function FindingsPageProvider({ getService, getPageObjects }: FtrProvider index: FINDINGS_LATEST_INDEX, body: { ...finding, - '@timestamp': new Date().toISOString(), + '@timestamp': finding['@timestamp'] ?? new Date().toISOString(), }, refresh: true, }) @@ -81,6 +87,20 @@ export function FindingsPageProvider({ getService, getPageObjects }: FtrProvider }, }; + const detectionRuleApi = { + remove: async () => { + await supertest + .post('/api/detection_engine/rules/_bulk_action?dry_run=false') + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .send({ + action: 'delete', + query: '', + }) + .expect(200); + }, + }; + const distributionBar = { filterBy: async (type: 'passed' | 'failed') => testSubjects.click(type === 'failed' ? 'distribution_bar_failed' : 'distribution_bar_passed'), @@ -203,6 +223,12 @@ export function FindingsPageProvider({ getService, getPageObjects }: FtrProvider await nonStaleElement.click(); } }, + + async openFlyoutAt(rowIndex: number) { + const table = await this.getElement(); + const flyoutButton = await table.findAllByTestSubject('findings_table_expand_column'); + await flyoutButton[rowIndex].click(); + }, }); const navigateToLatestFindingsPage = async () => { @@ -247,6 +273,41 @@ export function FindingsPageProvider({ getService, getPageObjects }: FtrProvider const notInstalledVulnerabilities = createNotInstalledObject('cnvm-integration-not-installed'); const notInstalledCSP = createNotInstalledObject('cloud_posture_page_package_not_installed'); + const createFlyoutObject = (tableTestSubject: string) => ({ + async getElement() { + return await testSubjects.find(tableTestSubject); + }, + async clickTakeActionButton() { + const element = await this.getElement(); + const button = await element.findByCssSelector('[data-test-subj="csp:take_action"] button'); + await button.click(); + return button; + }, + async clickTakeActionCreateRuleButton() { + await this.clickTakeActionButton(); + const button = await testSubjects.find('csp:create_rule'); + await button.click(); + return button; + }, + async getVisibleText(testSubj: string) { + const element = await this.getElement(); + return await (await element.findByTestSubject(testSubj)).getVisibleText(); + }, + }); + + const misconfigurationsFlyout = createFlyoutObject('findings_flyout'); + + const toastMessage = async (testSubj = 'csp:toast-success') => ({ + async getElement() { + return await testSubjects.find(testSubj); + }, + async clickToastMessageLink(linkTestSubj = 'csp:toast-success-link') { + const element = await this.getElement(); + const link = await element.findByTestSubject(linkTestSubj); + await link.click(); + }, + }); + return { navigateToLatestFindingsPage, navigateToVulnerabilities, @@ -259,5 +320,8 @@ export function FindingsPageProvider({ getService, getPageObjects }: FtrProvider index, waitForPluginInitialized, distributionBar, + misconfigurationsFlyout, + toastMessage, + detectionRuleApi, }; } diff --git a/x-pack/test/cloud_security_posture_functional/pages/findings_alerts.ts b/x-pack/test/cloud_security_posture_functional/pages/findings_alerts.ts new file mode 100644 index 0000000000000..53f0b765165ef --- /dev/null +++ b/x-pack/test/cloud_security_posture_functional/pages/findings_alerts.ts @@ -0,0 +1,236 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import Chance from 'chance'; +import type { FtrProviderContext } from '../ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + const pageObjects = getPageObjects(['common', 'findings', 'header']); + const chance = new Chance(); + + // We need to use a dataset for the tests to run + const data = [ + { + resource: { id: chance.guid(), name: `kubelet`, sub_type: 'lower case sub type' }, + result: { evaluation: chance.integer() % 2 === 0 ? 'passed' : 'failed' }, + rule: { + tags: ['CIS', 'CIS K8S'], + rationale: 'rationale steps for rule 1.1', + references: '1. https://elastic.co/rules/1.1', + name: 'Upper case rule name', + section: 'Upper case section', + benchmark: { + rule_number: '1.1', + id: 'cis_k8s', + posture_type: 'kspm', + name: 'CIS Kubernetes V1.23', + version: 'v1.0.0', + remediation: 'remediation guide', + }, + type: 'process', + }, + cluster_id: 'Upper case cluster id', + }, + { + '@timestamp': '2023-09-10T14:01:00.000Z', + resource: { id: chance.guid(), name: `Pod`, sub_type: 'Upper case sub type' }, + result: { evaluation: chance.integer() % 2 === 0 ? 'passed' : 'failed' }, + rule: { + tags: ['CIS', 'CIS K8S'], + rationale: 'rationale steps', + references: '1. https://elastic.co', + name: 'lower case rule name', + section: 'Another upper case section', + benchmark: { + rule_number: '1.2', + id: 'cis_k8s', + posture_type: 'kspm', + name: 'CIS Kubernetes V1.23', + version: 'v1.0.0', + remediation: 'remediation guide', + }, + type: 'process', + }, + cluster_id: 'Another Upper case cluster id', + }, + { + '@timestamp': '2023-09-10T14:02:00.000Z', + resource: { id: chance.guid(), name: `process`, sub_type: 'another lower case type' }, + result: { evaluation: 'passed' }, + rule: { + tags: ['CIS', 'CIS K8S'], + rationale: 'rationale steps', + references: '1. https://elastic.co', + name: 'Another upper case rule name', + section: 'lower case section', + benchmark: { + rule_number: '1.3', + id: 'cis_k8s', + posture_type: 'kspm', + name: 'CIS Kubernetes V1.23', + version: 'v1.0.0', + remediation: 'remediation guide', + }, + type: 'process', + }, + cluster_id: 'lower case cluster id', + }, + { + '@timestamp': '2023-09-10T14:03:00.000Z', + resource: { id: chance.guid(), name: `process`, sub_type: 'Upper case type again' }, + result: { evaluation: 'failed' }, + rule: { + tags: ['CIS', 'CIS K8S'], + rationale: 'rationale steps', + references: '1. https://elastic.co', + name: 'some lower case rule name', + section: 'another lower case section', + benchmark: { + rule_number: '1.4', + id: 'cis_k8s', + posture_type: 'kspm', + name: 'CIS Kubernetes V1.23', + version: 'v1.0.0', + remediation: 'remediation guide', + }, + type: 'process', + }, + cluster_id: 'another lower case cluster id', + }, + ]; + + const ruleName1 = data[0].rule.name; + + describe('Findings Page - Alerts', function () { + this.tags(['cloud_security_posture_findings_alerts']); + let findings: typeof pageObjects.findings; + let latestFindingsTable: typeof findings.latestFindingsTable; + let misconfigurationsFlyout: typeof findings.misconfigurationsFlyout; + + before(async () => { + findings = pageObjects.findings; + latestFindingsTable = findings.latestFindingsTable; + misconfigurationsFlyout = findings.misconfigurationsFlyout; + // Before we start any test we must wait for cloud_security_posture plugin to complete its initialization + await findings.waitForPluginInitialized(); + // Prepare mocked findings + await findings.index.remove(); + await findings.index.add(data); + }); + + after(async () => { + await findings.index.remove(); + await findings.detectionRuleApi.remove(); + }); + + beforeEach(async () => { + await findings.detectionRuleApi.remove(); + await findings.navigateToLatestFindingsPage(); + await retry.waitFor( + 'Findings table to be loaded', + async () => (await latestFindingsTable.getRowsCount()) === data.length + ); + pageObjects.header.waitUntilLoadingHasFinished(); + }); + + describe('Create detection rule', () => { + it('Creates a detection rule from the Take Action button and navigates to rule page', async () => { + await latestFindingsTable.openFlyoutAt(0); + await misconfigurationsFlyout.clickTakeActionCreateRuleButton(); + + expect( + await misconfigurationsFlyout.getVisibleText('csp:findings-flyout-alert-count') + ).to.be('0 alerts'); + + expect( + await misconfigurationsFlyout.getVisibleText('csp:findings-flyout-detection-rule-count') + ).to.be('1 detection rule'); + + const toastMessage = await (await findings.toastMessage()).getElement(); + expect(toastMessage).to.be.ok(); + + const toastMessageTitle = await toastMessage.findByTestSubject('csp:toast-success-title'); + expect(await toastMessageTitle.getVisibleText()).to.be(ruleName1); + + await (await findings.toastMessage()).clickToastMessageLink(); + + const rulePageTitle = await testSubjects.find('header-page-title'); + expect(await rulePageTitle.getVisibleText()).to.be(ruleName1); + }); + it('Creates a detection rule from the Alerts section and navigates to rule page', async () => { + await latestFindingsTable.openFlyoutAt(0); + const flyout = await misconfigurationsFlyout.getElement(); + + await ( + await flyout.findByTestSubject('csp:findings-flyout-create-detection-rule-link') + ).click(); + + expect( + await misconfigurationsFlyout.getVisibleText('csp:findings-flyout-alert-count') + ).to.be('0 alerts'); + + expect( + await misconfigurationsFlyout.getVisibleText('csp:findings-flyout-detection-rule-count') + ).to.be('1 detection rule'); + + const toastMessage = await (await findings.toastMessage()).getElement(); + expect(toastMessage).to.be.ok(); + + const toastMessageTitle = await toastMessage.findByTestSubject('csp:toast-success-title'); + expect(await toastMessageTitle.getVisibleText()).to.be(ruleName1); + + await (await findings.toastMessage()).clickToastMessageLink(); + + const rulePageTitle = await testSubjects.find('header-page-title'); + expect(await rulePageTitle.getVisibleText()).to.be(ruleName1); + }); + }); + describe('Rule details', () => { + it('The rule page contains the expected matching data', async () => { + await latestFindingsTable.openFlyoutAt(0); + await misconfigurationsFlyout.clickTakeActionCreateRuleButton(); + + await (await findings.toastMessage()).clickToastMessageLink(); + + const rulePageDescription = await testSubjects.find( + 'stepAboutRuleDetailsToggleDescriptionText' + ); + expect(await rulePageDescription.getVisibleText()).to.be(data[0].rule.rationale); + + const severity = await testSubjects.find('severity'); + expect(await severity.getVisibleText()).to.be('Low'); + + const referenceUrls = await testSubjects.find('urlsDescriptionReferenceLinkItem'); + expect(await referenceUrls.getVisibleText()).to.contain('https://elastic.co/rules/1.1'); + }); + }); + describe('Navigation', () => { + it('Clicking on count of Rules should navigate to the rules page with benchmark tags as a filter', async () => { + await latestFindingsTable.openFlyoutAt(0); + await misconfigurationsFlyout.clickTakeActionCreateRuleButton(); + const flyout = await misconfigurationsFlyout.getElement(); + await (await flyout.findByTestSubject('csp:findings-flyout-detection-rule-count')).click(); + + expect(await (await testSubjects.find('ruleName')).getVisibleText()).to.be(ruleName1); + }); + it('Clicking on count of Alerts should navigate to the alerts page', async () => { + await latestFindingsTable.openFlyoutAt(0); + await misconfigurationsFlyout.clickTakeActionCreateRuleButton(); + const flyout = await misconfigurationsFlyout.getElement(); + await (await flyout.findByTestSubject('csp:findings-flyout-alert-count')).click(); + + expect(await (await testSubjects.find('header-page-title')).getVisibleText()).to.be( + 'Alerts' + ); + }); + }); + }); +} diff --git a/x-pack/test/cloud_security_posture_functional/pages/index.ts b/x-pack/test/cloud_security_posture_functional/pages/index.ts index 1d30a3b27fda9..81e905ddaca35 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/index.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/index.ts @@ -12,6 +12,7 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('Cloud Security Posture', function () { loadTestFile(require.resolve('./findings_onboarding')); loadTestFile(require.resolve('./findings')); + loadTestFile(require.resolve('./findings_alerts')); loadTestFile(require.resolve('./compliance_dashboard')); }); } From 7f82102d720b5dffb5dafe2fd48a8ba760b9b4ec Mon Sep 17 00:00:00 2001 From: Alex Szabo Date: Mon, 25 Sep 2023 18:49:20 +0200 Subject: [PATCH 23/45] [Ops] ES Serverless image verification pipeline (#166054) ## Summary Prepares the serverless FTR tests to be runnable with a custom ES image. (`--esServerlessImage` cli arg) Creates a pipeline for testing and promoting ES Serverless docker releases. The job can be triggered here: https://buildkite.com/elastic/kibana-elasticsearch-serverless-verify-and-promote The three main env variables it takes: - BUILDKITE_BRANCH: the kibana branch to test with (maybe not as important) - BUILDKITE_COMMIT: the kibana commit to test with - ES_SERVERLESS_IMAGE: the elasticsearch serverless image, or tag to use from this repo: `docker.elastic.co/elasticsearch-ci/elasticsearch-serverless` ## TODOS: - [x] set `latest_verified` with full img path as default - [x] ~~find other CLIs that might need the `esServerlessImage` argument (if the docker runner has multiple usages)~~ | I confused the `yarn es docker` with this, because I thought we only run ES serverless in a docker container, but `elasticsearch` can also be run in docker. - [x] set `latest-compatible` or similar flag in a manifest in gcs for Elastic's use-case - [ ] ensure we can only verify "forward" (ie.: to avoid a parameterization on old versions to set our pointers back) [on a second thought, this might be kept as a feature to roll back (if we should ever need that)] There are two confusing things I couldn't sort out just yet: #### Ambiguity in --esServerlessImage We can either have 2 CLI args: one for an image tag, one for an image repo/image url, or we can have one (like I have it now) and interpret that in the code, it can be either the image url, or the tag. It's more flexible, but it's two things in one. Is it ok this way, or is it too confusing? e.g.: ``` node scripts/functional_tests --esFrom serverless --esServerlessImage docker.elastic.co/elasticsearch-ci/elasticsearch-serverless:git-8fc8f941bd4d --bail --config x-pack/test_serverless/functional/test_suites/security/config.ts # or node scripts/functional_tests --esFrom serverless --esServerlessImage latest --bail --config x-pack/test_serverless/functional/test_suites/security/config.ts ``` #### Ambiguity in the default image path The published ES Serverless images will sit on this image path: `docker.elastic.co/elasticsearch-ci/elasticsearch-serverless`, however, our one exception is the `latest-verified` which we will be tagging under a different path, where we have write rights: `docker.elastic.co/kibana-ci/elasticsearch-serverless:latest-verified`. Is it okay, that by default, we're searching in the `elasticsearch-ci` images for any tags as parameters (after all, all the new images will be published there), however our grand default will ultimately be `docker.elastic.co/kibana-ci/elasticsearch-serverless:latest-verified`. ## Links Buildkite: https://buildkite.com/elastic/kibana-elasticsearch-serverless-verify-and-promote eg.: https://buildkite.com/elastic/kibana-elasticsearch-serverless-verify-and-promote/builds/24 Closes: https://github.com/elastic/kibana/issues/162931 --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../verify_es_serverless_image.yml | 58 ++++++++++++++ .../promote_es_serverless_image.sh | 75 +++++++++++++++++++ packages/kbn-dev-cli-runner/src/flags.ts | 2 + packages/kbn-dev-cli-runner/src/help.ts | 8 +- packages/kbn-dev-cli-runner/src/run.ts | 1 + .../kbn-es/src/cli_commands/serverless.ts | 16 ++-- packages/kbn-es/src/utils/docker.test.ts | 10 ++- packages/kbn-es/src/utils/docker.ts | 49 ++++++++---- packages/kbn-test/src/es/es_test_config.ts | 4 + packages/kbn-test/src/es/test_es_cluster.ts | 16 +++- .../functional_tests/lib/run_elasticsearch.ts | 28 ++++++- .../src/functional_tests/run_tests/cli.ts | 1 + .../functional_tests/run_tests/flags.test.ts | 1 + .../src/functional_tests/run_tests/flags.ts | 10 +++ 14 files changed, 246 insertions(+), 33 deletions(-) create mode 100644 .buildkite/pipelines/es_serverless/verify_es_serverless_image.yml create mode 100755 .buildkite/scripts/steps/es_serverless/promote_es_serverless_image.sh diff --git a/.buildkite/pipelines/es_serverless/verify_es_serverless_image.yml b/.buildkite/pipelines/es_serverless/verify_es_serverless_image.yml new file mode 100644 index 0000000000000..f6cb21abdb682 --- /dev/null +++ b/.buildkite/pipelines/es_serverless/verify_es_serverless_image.yml @@ -0,0 +1,58 @@ +# https://buildkite.com/elastic/kibana-elasticsearch-serverless-verify-and-promote/ +agents: + queue: kibana-default + +steps: + - label: "Annotate runtime parameters" + command: | + buildkite-agent annotate --context es-serverless-image --style info "ES Serverless image: $ES_SERVERLESS_IMAGE" + buildkite-agent annotate --context kibana-commit --style info "Kibana build hash: $BUILDKITE_BRANCH / $BUILDKITE_COMMIT" + + - group: "(:kibana: x :elastic:) Trigger Kibana Serverless suite" + if: "build.env('SKIP_VERIFICATION') != '1' && build.env('SKIP_VERIFICATION') != 'true'" + steps: + - label: "Pre-Build" + command: .buildkite/scripts/lifecycle/pre_build.sh + key: pre-build + timeout_in_minutes: 10 + agents: + queue: kibana-default + + - label: "Build Kibana Distribution and Plugins" + command: .buildkite/scripts/steps/build_kibana.sh + agents: + queue: n2-16-spot + key: build + depends_on: pre-build + if: "build.env('KIBANA_BUILD_ID') == null || build.env('KIBANA_BUILD_ID') == ''" + timeout_in_minutes: 60 + retry: + automatic: + - exit_status: '-1' + limit: 3 + + - label: "Pick Test Group Run Order" + command: .buildkite/scripts/steps/test/pick_test_group_run_order.sh + agents: + queue: kibana-default + env: + FTR_CONFIGS_SCRIPT: 'TEST_ES_SERVERLESS_IMAGE=$ES_SERVERLESS_IMAGE .buildkite/scripts/steps/test/ftr_configs.sh' + FTR_CONFIG_PATTERNS: '**/test_serverless/**' + LIMIT_CONFIG_TYPE: 'functional' + retry: + automatic: + - exit_status: '*' + limit: 1 + + - wait: ~ + + - label: ":arrow_up::elastic::arrow_up: Promote docker image" + command: .buildkite/scripts/steps/es_serverless/promote_es_serverless_image.sh $ES_SERVERLESS_IMAGE + + - wait: ~ + + - label: 'Post-Build' + command: .buildkite/scripts/lifecycle/post_build.sh + timeout_in_minutes: 10 + agents: + queue: kibana-default diff --git a/.buildkite/scripts/steps/es_serverless/promote_es_serverless_image.sh b/.buildkite/scripts/steps/es_serverless/promote_es_serverless_image.sh new file mode 100755 index 0000000000000..c6bf1738fe144 --- /dev/null +++ b/.buildkite/scripts/steps/es_serverless/promote_es_serverless_image.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +set -euo pipefail + +source .buildkite/scripts/common/util.sh + +BASE_ES_SERVERLESS_REPO=docker.elastic.co/elasticsearch-ci/elasticsearch-serverless +TARGET_IMAGE=docker.elastic.co/kibana-ci/elasticsearch-serverless:latest-verified + +ES_SERVERLESS_BUCKET=kibana-ci-es-serverless-images +MANIFEST_FILE_NAME=latest-verified.json + +SOURCE_IMAGE_OR_TAG=$1 +if [[ $SOURCE_IMAGE_OR_TAG =~ :[a-zA-Z_-]+$ ]]; then + # $SOURCE_IMAGE_OR_TAG was a full image + SOURCE_IMAGE=$SOURCE_IMAGE_OR_TAG +else + # $SOURCE_IMAGE_OR_TAG was an image tag + SOURCE_IMAGE="$BASE_ES_SERVERLESS_REPO:$SOURCE_IMAGE_OR_TAG" +fi + +echo "--- Promoting ${SOURCE_IMAGE_OR_TAG} to ':latest-verified'" + +echo "Re-tagging $SOURCE_IMAGE -> $TARGET_IMAGE" + +echo "$KIBANA_DOCKER_PASSWORD" | docker login -u "$KIBANA_DOCKER_USERNAME" --password-stdin docker.elastic.co +docker pull "$SOURCE_IMAGE" +docker tag "$SOURCE_IMAGE" "$TARGET_IMAGE" +docker push "$TARGET_IMAGE" + +ORIG_IMG_DATA=$(docker inspect "$SOURCE_IMAGE") +ELASTIC_COMMIT_HASH=$(echo $ORIG_IMG_DATA | jq -r '.[].Config.Labels["org.opencontainers.image.revision"]') + +docker logout docker.elastic.co + +echo "Image push to $TARGET_IMAGE successful." +echo "Promotion successful! Henceforth, thou shall be named Sir $TARGET_IMAGE" + +MANIFEST_UPLOAD_PATH="Skipped" +if [[ "$UPLOAD_MANIFEST" =~ ^(1|true)$ && "$SOURCE_IMAGE_OR_TAG" =~ ^git-[0-9a-fA-F]{12}$ ]]; then + echo "--- Uploading latest-verified manifest to GCS" + cat << EOT >> $MANIFEST_FILE_NAME +{ + "build_url": "$BUILDKITE_BUILD_URL", + "kibana_commit": "$BUILDKITE_COMMIT", + "kibana_branch": "$BUILDKITE_BRANCH", + "elasticsearch_serverless_tag": "$SOURCE_IMAGE_OR_TAG", + "elasticsearch_serverless_image_url: "$SOURCE_IMAGE", + "elasticsearch_serverless_commit": "TODO: this currently can't be decided", + "elasticsearch_commit": "$ELASTIC_COMMIT_HASH", + "created_at": "`date`", + "timestamp": "`FORCE_COLOR=0 node -p 'Date.now()'`" +} +EOT + + gsutil -h "Cache-Control:no-cache, max-age=0, no-transform" \ + cp $MANIFEST_FILE_NAME "gs://$ES_SERVERLESS_BUCKET/$MANIFEST_FILE_NAME" + gsutil acl ch -u AllUsers:R "gs://$ES_SERVERLESS_BUCKET/$MANIFEST_FILE_NAME" + MANIFEST_UPLOAD_PATH="$MANIFEST_FILE_NAME" + +elif [[ "$UPLOAD_MANIFEST" =~ ^(1|true)$ ]]; then + echo "--- Skipping upload of latest-verified manifest to GCS, ES Serverless build tag is not pointing to a hash" +elif [[ "$SOURCE_IMAGE_OR_TAG" =~ ^git-[0-9a-fA-F]{12}$ ]]; then + echo "--- Skipping upload of latest-verified manifest to GCS, flag was not provided" +fi + +echo "--- Annotating build with info" +cat << EOT | buildkite-agent annotate --style "success" +

    Promotion successful!

    +
    New image: $TARGET_IMAGE +
    Source image: $SOURCE_IMAGE +
    Kibana commit: $BUILDKITE_COMMIT +
    Elasticsearch commit: $ELASTIC_COMMIT_HASH +
    Manifest file: $MANIFEST_UPLOAD_PATH +EOT diff --git a/packages/kbn-dev-cli-runner/src/flags.ts b/packages/kbn-dev-cli-runner/src/flags.ts index 595205c3e0333..d7b352333ae1b 100644 --- a/packages/kbn-dev-cli-runner/src/flags.ts +++ b/packages/kbn-dev-cli-runner/src/flags.ts @@ -27,6 +27,7 @@ export interface FlagOptions { allowUnexpected?: boolean; guessTypesForUnexpectedFlags?: boolean; help?: string; + examples?: string; alias?: { [key: string]: string | string[] }; boolean?: string[]; string?: string[]; @@ -47,6 +48,7 @@ export function mergeFlagOptions(global: FlagOptions = {}, local: FlagOptions = }, help: local.help, + examples: local.examples, allowUnexpected: !!(global.allowUnexpected || local.allowUnexpected), guessTypesForUnexpectedFlags: !!(global.allowUnexpected || local.allowUnexpected), diff --git a/packages/kbn-dev-cli-runner/src/help.ts b/packages/kbn-dev-cli-runner/src/help.ts index a7dc17aa43f17..f3e0e2c78e97f 100644 --- a/packages/kbn-dev-cli-runner/src/help.ts +++ b/packages/kbn-dev-cli-runner/src/help.ts @@ -36,11 +36,13 @@ export function getHelp({ usage, flagHelp, defaultLogLevel, + examples, }: { description?: string; usage?: string; flagHelp?: string; defaultLogLevel?: string; + examples?: string; }) { const optionHelp = joinAndTrimLines( dedent(flagHelp || ''), @@ -48,13 +50,17 @@ export function getHelp({ GLOBAL_FLAGS ); + const examplesHelp = examples ? joinAndTrimLines('Examples:', examples) : ''; + return ` ${dedent(usage || '') || DEFAULT_GLOBAL_USAGE} ${indent(dedent(description || 'Runs a dev task'), 2)} Options: - ${indent(optionHelp, 4)}\n\n`; + ${indent(optionHelp, 4)} +${examplesHelp ? `\n ${indent(examplesHelp, 4)}` : ''} +`; } export function getCommandLevelHelp({ diff --git a/packages/kbn-dev-cli-runner/src/run.ts b/packages/kbn-dev-cli-runner/src/run.ts index 08457caaebfd4..2ef90c2e2c27a 100644 --- a/packages/kbn-dev-cli-runner/src/run.ts +++ b/packages/kbn-dev-cli-runner/src/run.ts @@ -50,6 +50,7 @@ export async function run(fn: RunFn, options: RunOptions = {}) { usage: options.usage, flagHelp: options.flags?.help, defaultLogLevel: options.log?.defaultLevel, + examples: options.flags?.examples, }); if (flags.help) { diff --git a/packages/kbn-es/src/cli_commands/serverless.ts b/packages/kbn-es/src/cli_commands/serverless.ts index 7ee4f08fb94fe..c8b3018e6f669 100644 --- a/packages/kbn-es/src/cli_commands/serverless.ts +++ b/packages/kbn-es/src/cli_commands/serverless.ts @@ -13,9 +13,8 @@ import { getTimeReporter } from '@kbn/ci-stats-reporter'; import { Cluster } from '../cluster'; import { - SERVERLESS_REPO, - SERVERLESS_TAG, - SERVERLESS_IMG, + ES_SERVERLESS_REPO_ELASTICSEARCH, + ES_SERVERLESS_DEFAULT_IMAGE, DEFAULT_PORT, ServerlessOptions, } from '../utils'; @@ -28,9 +27,8 @@ export const serverless: Command = { return dedent` Options: - --tag Image tag of ES serverless to run from ${SERVERLESS_REPO} [default: ${SERVERLESS_TAG}] - --image Full path of ES serverless image to run, has precedence over tag. [default: ${SERVERLESS_IMG}] - + --tag Image tag of ES serverless to run from ${ES_SERVERLESS_REPO_ELASTICSEARCH} + --image Full path of ES serverless image to run, has precedence over tag. [default: ${ES_SERVERLESS_DEFAULT_IMAGE}] --background Start ES serverless without attaching to the first node's logs --basePath Path to the directory where the ES cluster will store data --clean Remove existing file system object store before running @@ -39,14 +37,14 @@ export const serverless: Command = { --ssl Enable HTTP SSL on the ES cluster --skipTeardown If this process exits, leave the ES cluster running in the background --waitForReady Wait for the ES cluster to be ready to serve requests - + -E Additional key=value settings to pass to ES -F Absolute paths for files to mount into containers Examples: - es serverless --tag git-fec36430fba2-x86_64 - es serverless --image docker.elastic.co/repo:tag + es serverless --tag git-fec36430fba2-x86_64 # loads ${ES_SERVERLESS_REPO_ELASTICSEARCH}:git-fec36430fba2-x86_64 + es serverless --image docker.elastic.co/kibana-ci/elasticsearch-serverless:latest-verified `; }, run: async (defaults = {}) => { diff --git a/packages/kbn-es/src/utils/docker.test.ts b/packages/kbn-es/src/utils/docker.test.ts index d48cddd6fdb6d..08edc2a17521d 100644 --- a/packages/kbn-es/src/utils/docker.test.ts +++ b/packages/kbn-es/src/utils/docker.test.ts @@ -23,7 +23,7 @@ import { runDockerContainer, runServerlessCluster, runServerlessEsNode, - SERVERLESS_IMG, + ES_SERVERLESS_DEFAULT_IMAGE, setupServerlessVolumes, stopServerlessCluster, teardownServerlessClusterSync, @@ -451,7 +451,7 @@ describe('runServerlessEsNode()', () => { const node = { params: ['--env', 'foo=bar', '--volume', 'foo/bar'], name: 'es01', - image: SERVERLESS_IMG, + image: ES_SERVERLESS_DEFAULT_IMAGE, }; test('should call the correct Docker command', async () => { @@ -462,7 +462,7 @@ describe('runServerlessEsNode()', () => { expect(execa.mock.calls[0][0]).toEqual('docker'); expect(execa.mock.calls[0][1]).toEqual( expect.arrayContaining([ - SERVERLESS_IMG, + ES_SERVERLESS_DEFAULT_IMAGE, ...node.params, '--name', node.name, @@ -530,7 +530,9 @@ describe('teardownServerlessClusterSync()', () => { teardownServerlessClusterSync(log, defaultOptions); expect(execa.commandSync.mock.calls).toHaveLength(2); - expect(execa.commandSync.mock.calls[0][0]).toEqual(expect.stringContaining(SERVERLESS_IMG)); + expect(execa.commandSync.mock.calls[0][0]).toEqual( + expect.stringContaining(ES_SERVERLESS_DEFAULT_IMAGE) + ); expect(execa.commandSync.mock.calls[1][0]).toEqual(`docker kill ${nodes.join(' ')}`); }); diff --git a/packages/kbn-es/src/utils/docker.ts b/packages/kbn-es/src/utils/docker.ts index 00a1d7ce9dc54..5ed22e094e6f8 100644 --- a/packages/kbn-es/src/utils/docker.ts +++ b/packages/kbn-es/src/utils/docker.ts @@ -38,9 +38,12 @@ import { import { SYSTEM_INDICES_SUPERUSER } from './native_realm'; import { waitUntilClusterReady } from './wait_until_cluster_ready'; -interface BaseOptions { - tag?: string; +interface ImageOptions { image?: string; + tag?: string; +} + +interface BaseOptions extends ImageOptions { port?: number; ssl?: boolean; /** Kill running cluster before starting a new cluster */ @@ -106,9 +109,10 @@ export const DOCKER_REPO = `${DOCKER_REGISTRY}/elasticsearch/elasticsearch`; export const DOCKER_TAG = `${pkg.version}-SNAPSHOT`; export const DOCKER_IMG = `${DOCKER_REPO}:${DOCKER_TAG}`; -export const SERVERLESS_REPO = `${DOCKER_REGISTRY}/elasticsearch-ci/elasticsearch-serverless`; -export const SERVERLESS_TAG = 'latest'; -export const SERVERLESS_IMG = `${SERVERLESS_REPO}:${SERVERLESS_TAG}`; +export const ES_SERVERLESS_REPO_KIBANA = `${DOCKER_REGISTRY}/kibana-ci/elasticsearch-serverless`; +export const ES_SERVERLESS_REPO_ELASTICSEARCH = `${DOCKER_REGISTRY}/elasticsearch-ci/elasticsearch-serverless`; +export const ES_SERVERLESS_LATEST_VERIFIED_TAG = 'latest-verified'; +export const ES_SERVERLESS_DEFAULT_IMAGE = `${ES_SERVERLESS_REPO_KIBANA}:${ES_SERVERLESS_LATEST_VERIFIED_TAG}`; // See for default cluster settings // https://github.com/elastic/elasticsearch-serverless/blob/main/serverless-build-tools/src/main/kotlin/elasticsearch.serverless-run.gradle.kts @@ -275,7 +279,12 @@ export function resolveDockerImage({ image, repo, defaultImg, -}: (ServerlessOptions | DockerOptions) & { repo: string; defaultImg: string }) { +}: { + tag?: string; + image?: string; + repo: string; + defaultImg: string; +}) { if (image) { if (!image.includes(DOCKER_REGISTRY)) { throw createCliError( @@ -525,11 +534,12 @@ export async function setupServerlessVolumes(log: ToolingLog, options: Serverles /** * Resolve the Serverless ES image based on defaults and CLI options */ -function getServerlessImage(options: ServerlessOptions) { +function getServerlessImage({ image, tag }: ImageOptions) { return resolveDockerImage({ - ...options, - repo: SERVERLESS_REPO, - defaultImg: SERVERLESS_IMG, + image, + tag, + repo: ES_SERVERLESS_REPO_ELASTICSEARCH, + defaultImg: ES_SERVERLESS_DEFAULT_IMAGE, }); } @@ -573,7 +583,10 @@ function getESClient(clientOptions: ClientOptions): Client { * Runs an ES Serverless Cluster through Docker */ export async function runServerlessCluster(log: ToolingLog, options: ServerlessOptions) { - const image = getServerlessImage(options); + const image = getServerlessImage({ + image: options.image, + tag: options.tag, + }); await setupDocker({ log, image, options }); const volumeCmd = await setupServerlessVolumes(log, options); @@ -686,8 +699,13 @@ export function teardownServerlessClusterSync(log: ToolingLog, options: Serverle /** * Resolve the Elasticsearch image based on defaults and CLI options */ -function getDockerImage(options: DockerOptions) { - return resolveDockerImage({ ...options, repo: DOCKER_REPO, defaultImg: DOCKER_IMG }); +function getDockerImage({ image, tag }: ImageOptions) { + return resolveDockerImage({ + image, + tag, + repo: DOCKER_REPO, + defaultImg: DOCKER_IMG, + }); } /** @@ -713,7 +731,10 @@ export async function runDockerContainer(log: ToolingLog, options: DockerOptions let image; if (!options.dockerCmd) { - image = getDockerImage(options); + image = getDockerImage({ + image: options.image, + tag: options.tag, + }); await setupDocker({ log, image, options }); } diff --git a/packages/kbn-test/src/es/es_test_config.ts b/packages/kbn-test/src/es/es_test_config.ts index c31728b0fd7d8..26827558b7bd3 100644 --- a/packages/kbn-test/src/es/es_test_config.ts +++ b/packages/kbn-test/src/es/es_test_config.ts @@ -27,6 +27,10 @@ class EsTestConfig { return process.env.TEST_ES_FROM || 'snapshot'; } + getESServerlessImage() { + return process.env.TEST_ES_SERVERLESS_IMAGE; + } + getTransportPort() { return process.env.TEST_ES_TRANSPORT_PORT || '9300-9400'; } diff --git a/packages/kbn-test/src/es/test_es_cluster.ts b/packages/kbn-test/src/es/test_es_cluster.ts index 3cd90d21d1d91..3c63960bdc0e5 100644 --- a/packages/kbn-test/src/es/test_es_cluster.ts +++ b/packages/kbn-test/src/es/test_es_cluster.ts @@ -70,6 +70,10 @@ export interface CreateTestEsClusterOptions { */ esArgs?: string[]; esFrom?: string; + esServerlessOptions?: { + image?: string; + tag?: string; + }; esJavaOpts?: string; /** * License to run your cluster under. Keep in mind that a `trial` license @@ -164,6 +168,7 @@ export function createTestEsCluster< writeLogsToPath, basePath = Path.resolve(REPO_ROOT, '.es'), esFrom = esTestConfig.getBuildFrom(), + esServerlessOptions, dataArchive, nodes = [{ name: 'node-01' }], esArgs: customEsArgs = [], @@ -236,9 +241,11 @@ export function createTestEsCluster< } else if (esFrom === 'snapshot') { installPath = (await firstNode.installSnapshot(config)).installPath; } else if (esFrom === 'serverless') { - return await firstNode.runServerless({ + await firstNode.runServerless({ basePath, esArgs: customEsArgs, + image: esServerlessOptions?.image, + tag: esServerlessOptions?.tag, port, clean: true, background: true, @@ -247,6 +254,7 @@ export function createTestEsCluster< kill: true, // likely don't need this but avoids any issues where the ESS cluster wasn't cleaned up waitForReady: true, }); + return; } else if (Path.isAbsolute(esFrom)) { installPath = esFrom; } else { @@ -275,9 +283,9 @@ export function createTestEsCluster< }); } - nodeStartPromises.push(async () => { + nodeStartPromises.push(() => { log.info(`[es] starting node ${node.name} on port ${nodePort}`); - return await this.nodes[i].start(installPath, { + return this.nodes[i].start(installPath, { password: config.password, esArgs: assignArgs(esArgs, overriddenArgs), esJavaOpts, @@ -292,7 +300,7 @@ export function createTestEsCluster< }); } - await Promise.all(extractDirectoryPromises.map(async (extract) => await extract())); + await Promise.all(extractDirectoryPromises.map((extract) => extract())); for (const start of nodeStartPromises) { await start(); } diff --git a/packages/kbn-test/src/functional_tests/lib/run_elasticsearch.ts b/packages/kbn-test/src/functional_tests/lib/run_elasticsearch.ts index f9c83161b521b..d298a1c1abaa4 100644 --- a/packages/kbn-test/src/functional_tests/lib/run_elasticsearch.ts +++ b/packages/kbn-test/src/functional_tests/lib/run_elasticsearch.ts @@ -12,11 +12,12 @@ import getPort from 'get-port'; import { REPO_ROOT } from '@kbn/repo-info'; import type { ArtifactLicense } from '@kbn/es'; import type { Config } from '../../functional_test_runner'; -import { createTestEsCluster } from '../../es'; +import { createTestEsCluster, esTestConfig } from '../../es'; interface RunElasticsearchOptions { log: ToolingLog; esFrom?: string; + esServerlessImage?: string; config: Config; onEarlyExit?: (msg: string) => void; logsDir?: string; @@ -32,6 +33,7 @@ type EsConfig = ReturnType; function getEsConfig({ config, esFrom = config.get('esTestCluster.from'), + esServerlessImage, }: RunElasticsearchOptions) { const ssl = !!config.get('esTestCluster.ssl'); const license: ArtifactLicense = config.get('esTestCluster.license'); @@ -50,6 +52,8 @@ function getEsConfig({ const serverless: boolean = config.get('serverless'); const files: string[] | undefined = config.get('esTestCluster.files'); + const esServerlessOptions = getESServerlessOptions(esServerlessImage, config); + return { ssl, license, @@ -57,6 +61,7 @@ function getEsConfig({ esJavaOpts, isSecurityEnabled, esFrom, + esServerlessOptions, port, password, dataArchive, @@ -129,6 +134,7 @@ async function startEsNode({ clusterName: `cluster-${name}`, esArgs: config.esArgs, esFrom: config.esFrom, + esServerlessOptions: config.esServerlessOptions, esJavaOpts: config.esJavaOpts, license: config.license, password: config.password, @@ -153,3 +159,23 @@ async function startEsNode({ return cluster; } + +function getESServerlessOptions(esServerlessImageFromArg: string | undefined, config: Config) { + const esServerlessImageUrlOrTag = + esServerlessImageFromArg || + esTestConfig.getESServerlessImage() || + (config.has('esTestCluster.esServerlessImage') && + config.get('esTestCluster.esServerlessImage')); + + if (esServerlessImageUrlOrTag) { + if (esServerlessImageUrlOrTag.includes(':')) { + return { + image: esServerlessImageUrlOrTag, + }; + } else { + return { + tag: esServerlessImageUrlOrTag, + }; + } + } +} diff --git a/packages/kbn-test/src/functional_tests/run_tests/cli.ts b/packages/kbn-test/src/functional_tests/run_tests/cli.ts index 19a003dd973cf..40a711ca9f6c2 100644 --- a/packages/kbn-test/src/functional_tests/run_tests/cli.ts +++ b/packages/kbn-test/src/functional_tests/run_tests/cli.ts @@ -26,6 +26,7 @@ export function runTestsCli() { { description: `Run Functional Tests`, usage: ` + Usage: node scripts/functional_tests --help node scripts/functional_tests [--config [--config ...]] node scripts/functional_tests [options] [-- --] diff --git a/packages/kbn-test/src/functional_tests/run_tests/flags.test.ts b/packages/kbn-test/src/functional_tests/run_tests/flags.test.ts index 0c9dae3a25794..77399605b29f4 100644 --- a/packages/kbn-test/src/functional_tests/run_tests/flags.test.ts +++ b/packages/kbn-test/src/functional_tests/run_tests/flags.test.ts @@ -42,6 +42,7 @@ describe('parse runTest flags', () => { ], "dryRun": false, "esFrom": undefined, + "esServerlessImage": undefined, "esVersion": , "grep": undefined, "installDir": undefined, diff --git a/packages/kbn-test/src/functional_tests/run_tests/flags.ts b/packages/kbn-test/src/functional_tests/run_tests/flags.ts index f4dd6beb26e80..3ba86999d3802 100644 --- a/packages/kbn-test/src/functional_tests/run_tests/flags.ts +++ b/packages/kbn-test/src/functional_tests/run_tests/flags.ts @@ -23,6 +23,7 @@ export const FLAG_OPTIONS: FlagOptions = { 'config', 'journey', 'esFrom', + 'esServerlessImage', 'kibana-install-dir', 'grep', 'include-tag', @@ -37,6 +38,7 @@ export const FLAG_OPTIONS: FlagOptions = { --config Define a FTR config that should be executed. Can be specified multiple times --journey Define a Journey that should be executed. Can be specified multiple times --esFrom Build Elasticsearch from source or run snapshot or serverless. Default: $TEST_ES_FROM or "snapshot" + --esServerlessImage When 'esFrom' is "serverless", this argument will be interpreted either as a tag within the ES Serverless repo, OR a full docker image path. --include-tag Tags that suites must include to be run, can be included multiple times --exclude-tag Tags that suites must NOT include to be run, can be included multiple times --include Files that must included to be run, can be included multiple times @@ -50,6 +52,13 @@ export const FLAG_OPTIONS: FlagOptions = { --updateSnapshots Replace inline and file snapshots with whatever is generated from the test --updateAll, -u Replace both baseline screenshots and snapshots `, + examples: ` +Run the latest verified, kibana-compatible ES Serverless image: + node scripts/functional_tests --config ./config.ts --esFrom serverless --esServerlessImage docker.elastic.co/kibana-ci/elasticsearch-serverless:latest-verified + +Run with a specific ES Serverless tag from the docker.elastic.co/elasticsearch-ci/elasticsearch-serverless repo: + node scripts/functional_tests --config ./config.ts --esFrom serverless --esServerlessImage git-fec36430fba2 + `, }; export function parseFlags(flags: FlagsReader) { @@ -75,6 +84,7 @@ export function parseFlags(flags: FlagsReader) { ? Path.resolve(REPO_ROOT, 'data/ftr_servers_logs', uuidV4()) : undefined, esFrom: flags.enum('esFrom', ['snapshot', 'source', 'serverless']), + esServerlessImage: flags.string('esServerlessImage'), installDir: flags.path('kibana-install-dir'), grep: flags.string('grep'), suiteTags: { From 5b24da796d3a992cd0e3eeb0262bd37564ba995b Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Mon, 25 Sep 2023 13:09:03 -0400 Subject: [PATCH 24/45] fix(slo): date range filter format (#166989) --- .../apm_transaction_duration.test.ts.snap | 16 ++++++++-------- .../apm_transaction_error_rate.test.ts.snap | 16 ++++++++-------- .../__snapshots__/histogram.test.ts.snap | 6 +++--- .../__snapshots__/kql_custom.test.ts.snap | 6 +++--- .../__snapshots__/metric_custom.test.ts.snap | 6 +++--- .../apm_transaction_duration.ts | 2 +- .../apm_transaction_error_rate.ts | 2 +- .../slo/transform_generators/histogram.ts | 2 +- .../slo/transform_generators/kql_custom.ts | 2 +- .../slo/transform_generators/metric_custom.ts | 2 +- 10 files changed, 30 insertions(+), 30 deletions(-) diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_duration.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_duration.test.ts.snap index 5f828ee51b625..aea9ba75f2863 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_duration.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_duration.test.ts.snap @@ -24,7 +24,7 @@ Object { Object { "range": Object { "@timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -130,7 +130,7 @@ Object { Object { "range": Object { "@timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -163,7 +163,7 @@ Object { Object { "range": Object { "@timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -277,7 +277,7 @@ Object { Object { "range": Object { "@timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -391,7 +391,7 @@ Object { Object { "range": Object { "@timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -505,7 +505,7 @@ Object { Object { "range": Object { "@timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -765,7 +765,7 @@ Object { Object { "range": Object { "@timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -1039,7 +1039,7 @@ Object { Object { "range": Object { "@timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_error_rate.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_error_rate.test.ts.snap index dc9278511a864..b7c4ebf0f6b8c 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_error_rate.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_error_rate.test.ts.snap @@ -20,7 +20,7 @@ Object { Object { "range": Object { "@timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -122,7 +122,7 @@ Object { Object { "range": Object { "@timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -151,7 +151,7 @@ Object { Object { "range": Object { "@timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -261,7 +261,7 @@ Object { Object { "range": Object { "@timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -371,7 +371,7 @@ Object { Object { "range": Object { "@timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -481,7 +481,7 @@ Object { Object { "range": Object { "@timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -730,7 +730,7 @@ Object { Object { "range": Object { "@timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -993,7 +993,7 @@ Object { Object { "range": Object { "@timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/histogram.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/histogram.test.ts.snap index ee4001303fec5..ad100c4662fe9 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/histogram.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/histogram.test.ts.snap @@ -51,7 +51,7 @@ Object { Object { "range": Object { "log_timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -232,7 +232,7 @@ Object { Object { "range": Object { "log_timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -488,7 +488,7 @@ Object { Object { "range": Object { "log_timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap index 126437173f84a..3297a8c513821 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap @@ -92,7 +92,7 @@ Object { Object { "range": Object { "log_timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -247,7 +247,7 @@ Object { Object { "range": Object { "log_timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -477,7 +477,7 @@ Object { Object { "range": Object { "log_timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/metric_custom.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/metric_custom.test.ts.snap index ced0801d859d4..362b1d4a9e01e 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/metric_custom.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/metric_custom.test.ts.snap @@ -63,7 +63,7 @@ Object { Object { "range": Object { "log_timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -256,7 +256,7 @@ Object { Object { "range": Object { "log_timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, @@ -524,7 +524,7 @@ Object { Object { "range": Object { "log_timestamp": Object { - "gte": "now-7d", + "gte": "now-7d/d", }, }, }, diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_duration.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_duration.ts index 3dd6469a7f2c5..171a5ca15e2de 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_duration.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_duration.ts @@ -72,7 +72,7 @@ export class ApmTransactionDurationTransformGenerator extends TransformGenerator { range: { '@timestamp': { - gte: `now-${slo.timeWindow.duration.format()}`, + gte: `now-${slo.timeWindow.duration.format()}/d`, }, }, }, diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_error_rate.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_error_rate.ts index 3818111c70df2..d038876f5ee9d 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_error_rate.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_error_rate.ts @@ -72,7 +72,7 @@ export class ApmTransactionErrorRateTransformGenerator extends TransformGenerato { range: { '@timestamp': { - gte: `now-${slo.timeWindow.duration.format()}`, + gte: `now-${slo.timeWindow.duration.format()}/d`, }, }, }, diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/histogram.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/histogram.ts index 654f8d67a3673..844703003257a 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/histogram.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/histogram.ts @@ -54,7 +54,7 @@ export class HistogramTransformGenerator extends TransformGenerator { { range: { [indicator.params.timestampField]: { - gte: `now-${slo.timeWindow.duration.format()}`, + gte: `now-${slo.timeWindow.duration.format()}/d`, }, }, }, diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.ts index 8321a0cb7172e..02c7757ec1362 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.ts @@ -49,7 +49,7 @@ export class KQLCustomTransformGenerator extends TransformGenerator { { range: { [indicator.params.timestampField]: { - gte: `now-${slo.timeWindow.duration.format()}`, + gte: `now-${slo.timeWindow.duration.format()}/d`, }, }, }, diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/metric_custom.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/metric_custom.ts index 52209533f828c..063e6fbe1e3dc 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/metric_custom.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/metric_custom.ts @@ -52,7 +52,7 @@ export class MetricCustomTransformGenerator extends TransformGenerator { { range: { [indicator.params.timestampField]: { - gte: `now-${slo.timeWindow.duration.format()}`, + gte: `now-${slo.timeWindow.duration.format()}/d`, }, }, }, From 93ce98831a900cc7f7cd1e91ac6f51bc57a67006 Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Mon, 25 Sep 2023 20:38:22 +0300 Subject: [PATCH 25/45] [ES|QL] Hides system indices (#166909) ## Summary Closes https://github.com/elastic/kibana/issues/166874 Hides indices starting with . (and considered as system from the autocomplete) image Followed the exact pattern that the dataview management page is using. --- .../kbn-text-based-editor/src/helpers.test.ts | 31 +++++++++++++++++-- packages/kbn-text-based-editor/src/helpers.ts | 10 ++++++ .../src/text_based_languages_editor.tsx | 8 ++--- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/packages/kbn-text-based-editor/src/helpers.test.ts b/packages/kbn-text-based-editor/src/helpers.test.ts index 5f1546ccc138e..f7b100419b2c7 100644 --- a/packages/kbn-text-based-editor/src/helpers.test.ts +++ b/packages/kbn-text-based-editor/src/helpers.test.ts @@ -5,8 +5,14 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - -import { parseErrors, parseWarning, getInlineEditorText, getWrappedInPipesCode } from './helpers'; +import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; +import { + parseErrors, + parseWarning, + getInlineEditorText, + getWrappedInPipesCode, + getIndicesForAutocomplete, +} from './helpers'; describe('helpers', function () { describe('parseErrors', function () { @@ -159,4 +165,25 @@ describe('helpers', function () { expect(code).toEqual('FROM index1 | keep field1, field2 | order field1'); }); }); + + describe('getIndicesForAutocomplete', function () { + it('should not return system indices', async function () { + const dataViewsMock = dataViewPluginMocks.createStartContract(); + const updatedDataViewsMock = { + ...dataViewsMock, + getIndices: jest.fn().mockResolvedValue([ + { + name: '.system1', + title: 'system1', + }, + { + name: 'logs', + title: 'logs', + }, + ]), + }; + const indices = await getIndicesForAutocomplete(updatedDataViewsMock); + expect(indices).toStrictEqual(['logs']); + }); + }); }); diff --git a/packages/kbn-text-based-editor/src/helpers.ts b/packages/kbn-text-based-editor/src/helpers.ts index 6b4e99f6e3093..8932276695117 100644 --- a/packages/kbn-text-based-editor/src/helpers.ts +++ b/packages/kbn-text-based-editor/src/helpers.ts @@ -10,6 +10,7 @@ import { useRef } from 'react'; import useDebounce from 'react-use/lib/useDebounce'; import { monaco } from '@kbn/monaco'; import { i18n } from '@kbn/i18n'; +import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; export interface MonacoError { message: string; @@ -172,3 +173,12 @@ export const getWrappedInPipesCode = (code: string, isWrapped: boolean): string }); return codeNoLines.join(isWrapped ? ' | ' : '\n| '); }; + +export const getIndicesForAutocomplete = async (dataViews: DataViewsPublicPluginStart) => { + const indices = await dataViews.getIndices({ + showAllIndices: false, + pattern: '*', + isRollupIndex: () => false, + }); + return indices.filter((index) => !index.name.startsWith('.')).map((i) => i.name); +}; diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx index fc86f7ca1cac6..b1f1708262743 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx @@ -56,6 +56,7 @@ import { getDocumentationSections, MonacoError, getWrappedInPipesCode, + getIndicesForAutocomplete, } from './helpers'; import { EditorFooter } from './editor_footer'; import { ResizableButton } from './resizable_button'; @@ -371,12 +372,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ const getSourceIdentifiers: ESQLCustomAutocompleteCallbacks['getSourceIdentifiers'] = useCallback(async () => { - const indices = await dataViews.getIndices({ - showAllIndices: false, - pattern: '*', - isRollupIndex: () => false, - }); - return indices.map((i) => i.name); + return await getIndicesForAutocomplete(dataViews); }, [dataViews]); const getFieldsIdentifiers: ESQLCustomAutocompleteCallbacks['getFieldsIdentifiers'] = useCallback( From 3f03264dc024a0e2abdd610c774048df861d6c38 Mon Sep 17 00:00:00 2001 From: Paul Tavares <56442535+paul-tavares@users.noreply.github.com> Date: Mon, 25 Sep 2023 13:46:35 -0400 Subject: [PATCH 26/45] [Security Solution][Endpoint] Refactor Cypress `login` task and ensure consistent use of users across ESS and Serverless tests (#166958) ## Summary - Cypress `login` task refactored: - `login(user?)` : logs use in using the default `user` or one of the users supported by security solution and endpoint management tests - `login.with(username, password)` : Logs a user in by using `username` and `password` - `login.withCustomRole(role)` : creates the provided `role`, creates a user for it by the same role name and logs in with it - The Cypress process for loading users into Kibana only applies to non-serverless (at the moment). For serverless, it only validates that the `username` being used is one of the approved user names that applies to serverless - FYI: the creation/availability of serverless roles/users for testing is an ongoing effort by the kibana ops team - New generic `RoleAndUserLoader` class. Is initialized with an map of `Roles` and provide a standard interface for loading them. - A sub-class (`EndpointSecurityTestRolesLoader`) was also created for the endpoint security test users, which uses the existing set of role definitions - The `resolver_generator_script` was also updated to use the new `EndpointSecurityTestRolesLoader` class for handling the `--rbacUser` argument --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../management/cypress/common/constants.ts | 21 ++ .../public/management/cypress/cypress.d.ts | 20 +- .../artifact_tabs_in_policy_details.cy.ts | 15 +- .../e2e/artifacts/artifacts_mocked_data.cy.ts | 15 +- .../e2e/automated_response_actions/form.cy.ts | 12 +- .../no_license.cy.ts | 4 +- ...dpoint_list_with_security_essentials.cy.ts | 4 +- .../serverless/feature_access/complete.cy.ts | 4 +- .../complete_with_endpoint.cy.ts | 4 +- .../feature_access/essentials.cy.ts | 4 +- .../essentials_with_endpoint.cy.ts | 4 +- ...icy_details_with_security_essentials.cy.ts | 4 +- .../roles/complete_with_endpoint_roles.cy.ts | 20 +- .../essentials_with_endpoint.roles.cy.ts | 22 +- .../role_with_artifact_read_privilege.ts | 30 ++ .../cypress/support/data_loaders.ts | 116 ++++++- .../public/management/cypress/tasks/login.ts | 295 +++++------------- .../cypress/tasks/login_serverless.ts | 103 ------ .../public/management/cypress/tsconfig.json | 1 + .../public/management/cypress/types.ts | 10 + .../scripts/endpoint/common/constants.ts | 5 + .../endpoint/common/role_and_user_loader.ts | 175 +++++++++++ .../endpoint/common/roles_users/index.ts | 139 +++++++++ .../common/roles_users/rule_author.ts | 36 +++ .../endpoint/common/roles_users/t3_analyst.ts | 39 +++ .../endpoint/resolver_generator_script.ts | 73 +---- 26 files changed, 714 insertions(+), 461 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/management/cypress/common/constants.ts create mode 100644 x-pack/plugins/security_solution/public/management/cypress/fixtures/role_with_artifact_read_privilege.ts delete mode 100644 x-pack/plugins/security_solution/public/management/cypress/tasks/login_serverless.ts create mode 100644 x-pack/plugins/security_solution/scripts/endpoint/common/role_and_user_loader.ts create mode 100644 x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/index.ts create mode 100644 x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/rule_author.ts create mode 100644 x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/t3_analyst.ts diff --git a/x-pack/plugins/security_solution/public/management/cypress/common/constants.ts b/x-pack/plugins/security_solution/public/management/cypress/common/constants.ts new file mode 100644 index 0000000000000..41f08f438e3f8 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/cypress/common/constants.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { EndpointSecurityRoleNames } from '../../../../scripts/endpoint/common/roles_users'; + +export type KibanaKnownUserAccounts = keyof typeof KIBANA_KNOWN_DEFAULT_ACCOUNTS; + +export type SecurityTestUser = EndpointSecurityRoleNames | KibanaKnownUserAccounts; + +/** + * List of kibana system accounts + */ +export const KIBANA_KNOWN_DEFAULT_ACCOUNTS = { + elastic: 'elastic', + elastic_serverless: 'elastic_serverless', + system_indices_superuser: 'system_indices_superuser', +} as const; diff --git a/x-pack/plugins/security_solution/public/management/cypress/cypress.d.ts b/x-pack/plugins/security_solution/public/management/cypress/cypress.d.ts index 4d84dc88af9c9..a4037e32632a5 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/cypress.d.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/cypress.d.ts @@ -17,7 +17,12 @@ import type { HostPolicyResponse, LogsEndpointActionResponse, } from '../../../common/endpoint/types'; -import type { IndexEndpointHostsCyTaskOptions, HostActionResponse } from './types'; +import type { + HostActionResponse, + IndexEndpointHostsCyTaskOptions, + LoadUserAndRoleCyTaskOptions, + CreateUserAndRoleCyTaskOptions, +} from './types'; import type { DeleteIndexedFleetEndpointPoliciesResponse, IndexedFleetEndpointPolicyResponse, @@ -32,6 +37,7 @@ import type { DeletedIndexedEndpointRuleAlerts, IndexedEndpointRuleAlerts, } from '../../../common/endpoint/data_loaders/index_endpoint_rule_alerts'; +import type { LoadedRoleAndUser } from '../../../scripts/endpoint/common/role_and_user_loader'; declare global { namespace Cypress { @@ -185,6 +191,18 @@ declare global { arg: { hostname: string; path: string; password?: string }, options?: Partial ): Chainable; + + task( + name: 'loadUserAndRole', + arg: LoadUserAndRoleCyTaskOptions, + options?: Partial + ): Chainable; + + task( + name: 'createUserAndRole', + arg: CreateUserAndRoleCyTaskOptions, + options?: Partial + ): Chainable; } } } diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifact_tabs_in_policy_details.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifact_tabs_in_policy_details.cy.ts index 39ebae1825365..8610ac1fc3ba5 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifact_tabs_in_policy_details.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifact_tabs_in_policy_details.cy.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { getRoleWithArtifactReadPrivilege } from '../../fixtures/role_with_artifact_read_privilege'; import { getEndpointSecurityPolicyManager } from '../../../../../scripts/endpoint/common/roles_users/endpoint_security_policy_manager'; import { getArtifactsListTestsData } from '../../fixtures/artifacts_page'; import { visitPolicyDetailsPage } from '../../screens/policy_details'; @@ -16,27 +17,21 @@ import { yieldFirstPolicyID, } from '../../tasks/artifacts'; import { loadEndpointDataForEventFiltersIfNeeded } from '../../tasks/load_endpoint_data'; -import { - getRoleWithArtifactReadPrivilege, - login, - loginWithCustomRole, - loginWithRole, - ROLE, -} from '../../tasks/login'; +import { login, ROLE } from '../../tasks/login'; import { performUserActions } from '../../tasks/perform_user_actions'; const loginWithPrivilegeAll = () => { - loginWithRole(ROLE.endpoint_security_policy_manager); + login(ROLE.endpoint_policy_manager); }; const loginWithPrivilegeRead = (privilegePrefix: string) => { const roleWithArtifactReadPrivilege = getRoleWithArtifactReadPrivilege(privilegePrefix); - loginWithCustomRole('roleWithArtifactReadPrivilege', roleWithArtifactReadPrivilege); + login.withCustomRole({ name: 'roleWithArtifactReadPrivilege', ...roleWithArtifactReadPrivilege }); }; const loginWithPrivilegeNone = (privilegePrefix: string) => { const roleWithoutArtifactPrivilege = getRoleWithoutArtifactPrivilege(privilegePrefix); - loginWithCustomRole('roleWithoutArtifactPrivilege', roleWithoutArtifactPrivilege); + login.withCustomRole({ name: 'roleWithoutArtifactPrivilege', ...roleWithoutArtifactPrivilege }); }; const getRoleWithoutArtifactPrivilege = (privilegePrefix: string) => { diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifacts_mocked_data.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifacts_mocked_data.cy.ts index 8f575282ad3f7..86cd86dd797b7 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifacts_mocked_data.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifacts_mocked_data.cy.ts @@ -5,13 +5,8 @@ * 2.0. */ -import { - getRoleWithArtifactReadPrivilege, - login, - loginWithCustomRole, - loginWithRole, - ROLE, -} from '../../tasks/login'; +import { getRoleWithArtifactReadPrivilege } from '../../fixtures/role_with_artifact_read_privilege'; +import { login, ROLE } from '../../tasks/login'; import { loadPage } from '../../tasks/common'; import { getArtifactsListTestsData } from '../../fixtures/artifacts_page'; @@ -20,18 +15,18 @@ import { performUserActions } from '../../tasks/perform_user_actions'; import { loadEndpointDataForEventFiltersIfNeeded } from '../../tasks/load_endpoint_data'; const loginWithWriteAccess = (url: string) => { - loginWithRole(ROLE.endpoint_security_policy_manager); + login(ROLE.endpoint_policy_manager); loadPage(url); }; const loginWithReadAccess = (privilegePrefix: string, url: string) => { const roleWithArtifactReadPrivilege = getRoleWithArtifactReadPrivilege(privilegePrefix); - loginWithCustomRole('roleWithArtifactReadPrivilege', roleWithArtifactReadPrivilege); + login.withCustomRole({ name: 'roleWithArtifactReadPrivilege', ...roleWithArtifactReadPrivilege }); loadPage(url); }; const loginWithoutAccess = (url: string) => { - loginWithRole(ROLE.t1_analyst); + login(ROLE.t1_analyst); loadPage(url); }; diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts index 84f6903c35a9b..eb5bae8624475 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts @@ -16,12 +16,12 @@ import { } from '../../tasks/response_actions'; import { cleanupRule, generateRandomStringName, loadRule } from '../../tasks/api_fixtures'; import { RESPONSE_ACTION_TYPES } from '../../../../../common/api/detection_engine'; -import { loginWithRole, ROLE } from '../../tasks/login'; +import { login, ROLE } from '../../tasks/login'; describe('Form', { tags: '@ess' }, () => { describe('User with no access can not create an endpoint response action', () => { before(() => { - loginWithRole(ROLE.endpoint_response_actions_no_access); + login(ROLE.endpoint_response_actions_no_access); }); it('no endpoint response action option during rule creation', () => { @@ -36,7 +36,7 @@ describe('Form', { tags: '@ess' }, () => { const [ruleName, ruleDescription] = generateRandomStringName(2); before(() => { - loginWithRole(ROLE.endpoint_response_actions_access); + login(ROLE.endpoint_response_actions_access); }); after(() => { cleanupRule(ruleId); @@ -94,7 +94,7 @@ describe('Form', { tags: '@ess' }, () => { }); }); beforeEach(() => { - loginWithRole(ROLE.endpoint_response_actions_access); + login(ROLE.endpoint_response_actions_access); }); after(() => { cleanupRule(ruleId); @@ -146,7 +146,7 @@ describe('Form', { tags: '@ess' }, () => { const [ruleName, ruleDescription] = generateRandomStringName(2); before(() => { - loginWithRole(ROLE.endpoint_response_actions_no_access); + login(ROLE.endpoint_response_actions_no_access); }); it('response actions are disabled', () => { @@ -166,7 +166,7 @@ describe('Form', { tags: '@ess' }, () => { loadRule().then((res) => { ruleId = res.id; }); - loginWithRole(ROLE.endpoint_response_actions_no_access); + login(ROLE.endpoint_response_actions_no_access); }); after(() => { cleanupRule(ruleId); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/no_license.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/no_license.cy.ts index edbaa90d3200c..eb6191ece0460 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/no_license.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/no_license.cy.ts @@ -9,7 +9,7 @@ import { disableExpandableFlyoutAdvancedSettings } from '../../tasks/common'; import { APP_ALERTS_PATH } from '../../../../../common/constants'; import { closeAllToasts } from '../../tasks/toasts'; import { fillUpNewRule } from '../../tasks/response_actions'; -import { login, loginWithRole, ROLE } from '../../tasks/login'; +import { login, ROLE } from '../../tasks/login'; import { generateRandomStringName } from '../../tasks/utils'; import type { ReturnTypeFromChainable } from '../../types'; import { indexEndpointHosts } from '../../tasks/index_endpoint_hosts'; @@ -20,7 +20,7 @@ describe('No License', { tags: '@ess', env: { ftrConfig: { license: 'basic' } } const [ruleName, ruleDescription] = generateRandomStringName(2); before(() => { - loginWithRole(ROLE.endpoint_response_actions_access); + login(ROLE.endpoint_response_actions_access); }); it('response actions are disabled', () => { diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/endpoint_list_with_security_essentials.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/endpoint_list_with_security_essentials.cy.ts index 58c41539361c5..32800978a968e 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/endpoint_list_with_security_essentials.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/endpoint_list_with_security_essentials.cy.ts @@ -7,7 +7,7 @@ import type { CyIndexEndpointHosts } from '../../tasks/index_endpoint_hosts'; import { indexEndpointHosts } from '../../tasks/index_endpoint_hosts'; -import { loginServerless } from '../../tasks/login_serverless'; +import { login } from '../../tasks/login'; import { getConsoleActionMenuItem, getUnIsolateActionMenuItem, @@ -42,7 +42,7 @@ describe( }); beforeEach(() => { - loginServerless(); + login(); visitEndpointList(); openRowActionMenu(); }); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/complete.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/complete.cy.ts index 7c4323b2aa689..dba7166b9a9e8 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/complete.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/complete.cy.ts @@ -6,7 +6,7 @@ */ import { ensureResponseActionAuthzAccess } from '../../../tasks/response_actions'; -import { loginServerless, ServerlessUser } from '../../../tasks/login_serverless'; +import { login, ROLE } from '../../../tasks/login'; import { RESPONSE_ACTION_API_COMMANDS_NAMES } from '../../../../../../common/endpoint/service/response_actions/constants'; import { getNoPrivilegesPage } from '../../../screens/common'; import { getEndpointManagementPageList } from '../../../screens'; @@ -31,7 +31,7 @@ describe( let password: string; beforeEach(() => { - loginServerless(ServerlessUser.ENDPOINT_OPERATIONS_ANALYST).then((response) => { + login(ROLE.endpoint_operations_analyst).then((response) => { username = response.username; password = response.password; }); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/complete_with_endpoint.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/complete_with_endpoint.cy.ts index f3ae8b85a9f24..3c028b9e25040 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/complete_with_endpoint.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/complete_with_endpoint.cy.ts @@ -6,7 +6,7 @@ */ import { ensureResponseActionAuthzAccess } from '../../../tasks/response_actions'; -import { loginServerless, ServerlessUser } from '../../../tasks/login_serverless'; +import { login, ROLE } from '../../../tasks/login'; import { RESPONSE_ACTION_API_COMMANDS_NAMES } from '../../../../../../common/endpoint/service/response_actions/constants'; import { getEndpointManagementPageList, @@ -33,7 +33,7 @@ describe( let password: string; beforeEach(() => { - loginServerless(ServerlessUser.ENDPOINT_OPERATIONS_ANALYST).then((response) => { + login(ROLE.endpoint_operations_analyst).then((response) => { username = response.username; password = response.password; }); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/essentials.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/essentials.cy.ts index 900a5d81a9f46..fed4494722df5 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/essentials.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/essentials.cy.ts @@ -6,7 +6,7 @@ */ import { ensureResponseActionAuthzAccess } from '../../../tasks/response_actions'; -import { loginServerless, ServerlessUser } from '../../../tasks/login_serverless'; +import { login, ROLE } from '../../../tasks/login'; import { RESPONSE_ACTION_API_COMMANDS_NAMES } from '../../../../../../common/endpoint/service/response_actions/constants'; import { getNoPrivilegesPage } from '../../../screens/common'; import { getEndpointManagementPageList } from '../../../screens'; @@ -33,7 +33,7 @@ describe( let password: string; beforeEach(() => { - loginServerless(ServerlessUser.ENDPOINT_OPERATIONS_ANALYST).then((response) => { + login(ROLE.endpoint_operations_analyst).then((response) => { username = response.username; password = response.password; }); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/essentials_with_endpoint.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/essentials_with_endpoint.cy.ts index 7196b73f6813a..172f850e44b7c 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/essentials_with_endpoint.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/essentials_with_endpoint.cy.ts @@ -6,7 +6,7 @@ */ import { ensureResponseActionAuthzAccess } from '../../../tasks/response_actions'; -import { loginServerless, ServerlessUser } from '../../../tasks/login_serverless'; +import { login, ROLE } from '../../../tasks/login'; import { RESPONSE_ACTION_API_COMMANDS_NAMES } from '../../../../../../common/endpoint/service/response_actions/constants'; import { getEndpointManagementPageMap, @@ -41,7 +41,7 @@ describe( let password: string; beforeEach(() => { - loginServerless(ServerlessUser.ENDPOINT_OPERATIONS_ANALYST).then((response) => { + login(ROLE.endpoint_operations_analyst).then((response) => { username = response.username; password = response.password; }); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/policy_details_with_security_essentials.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/policy_details_with_security_essentials.cy.ts index faf9aba6237b3..e1516bb08e10e 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/policy_details_with_security_essentials.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/policy_details_with_security_essentials.cy.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { loginServerless } from '../../tasks/login_serverless'; +import { login } from '../../tasks/login'; import { visitPolicyDetailsPage } from '../../screens/policy_details'; import type { IndexedFleetEndpointPolicyResponse } from '../../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy'; @@ -35,7 +35,7 @@ describe( }); beforeEach(() => { - loginServerless(); + login(); visitPolicyDetailsPage(loadedPolicyData.integrationPolicies[0].id); }); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/roles/complete_with_endpoint_roles.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/roles/complete_with_endpoint_roles.cy.ts index 879948a65c47d..534b681c2aeb4 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/roles/complete_with_endpoint_roles.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/roles/complete_with_endpoint_roles.cy.ts @@ -8,7 +8,7 @@ import { pick } from 'lodash'; import type { CyIndexEndpointHosts } from '../../../tasks/index_endpoint_hosts'; import { indexEndpointHosts } from '../../../tasks/index_endpoint_hosts'; -import { loginServerless, ServerlessUser } from '../../../tasks/login_serverless'; +import { login, ROLE } from '../../../tasks/login'; import { ensurePolicyDetailsPageAuthzAccess } from '../../../screens/policy_details'; import type { EndpointArtifactPageId } from '../../../screens'; import { @@ -63,12 +63,12 @@ describe( }); // roles `t1_analyst` and `t2_analyst` are very similar with exception of one page - (['t1_analyst', `t2_analyst`] as ServerlessUser[]).forEach((roleName) => { + (['t1_analyst', `t2_analyst`] as ROLE[]).forEach((roleName) => { describe(`for role: ${roleName}`, () => { const deniedPages = allPages.filter((page) => page.id !== 'endpointList'); beforeEach(() => { - loginServerless(roleName); + login(roleName); }); it('should have READ access to Endpoint list page', () => { @@ -124,7 +124,7 @@ describe( const deniedResponseActions = pick(consoleHelpPanelResponseActionsTestSubj, 'execute'); beforeEach(() => { - loginServerless(ServerlessUser.T3_ANALYST); + login(ROLE.t3_analyst); }); it('should have access to Endpoint list page', () => { @@ -176,7 +176,7 @@ describe( const deniedPages = allPages.filter(({ id }) => id !== 'blocklist' && id !== 'endpointList'); beforeEach(() => { - loginServerless(ServerlessUser.THREAT_INTELLIGENCE_ANALYST); + login(ROLE.threat_intelligence_analyst); }); it('should have access to Endpoint list page', () => { @@ -221,7 +221,7 @@ describe( ]; beforeEach(() => { - loginServerless(ServerlessUser.RULE_AUTHOR); + login(ROLE.rule_author); }); for (const { id, title } of artifactPagesFullAccess) { @@ -272,7 +272,7 @@ describe( const grantedAccessPages = [pageById.endpointList, pageById.policyList]; beforeEach(() => { - loginServerless(ServerlessUser.SOC_MANAGER); + login(ROLE.soc_manager); }); for (const { id, title } of artifactPagesFullAccess) { @@ -319,7 +319,7 @@ describe( const grantedAccessPages = [pageById.endpointList, pageById.policyList]; beforeEach(() => { - loginServerless(ServerlessUser.ENDPOINT_OPERATIONS_ANALYST); + login(ROLE.endpoint_operations_analyst); }); for (const { id, title } of artifactPagesFullAccess) { @@ -350,7 +350,7 @@ describe( }); }); - (['platform_engineer', 'endpoint_policy_manager'] as ServerlessUser[]).forEach((roleName) => { + (['platform_engineer', 'endpoint_policy_manager'] as ROLE[]).forEach((roleName) => { describe(`for role: ${roleName}`, () => { const artifactPagesFullAccess = [ pageById.trustedApps, @@ -361,7 +361,7 @@ describe( const grantedAccessPages = [pageById.endpointList, pageById.policyList]; beforeEach(() => { - loginServerless(roleName); + login(roleName); }); for (const { id, title } of artifactPagesFullAccess) { diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/roles/essentials_with_endpoint.roles.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/roles/essentials_with_endpoint.roles.cy.ts index fec6a0f803afb..6cf3ab727980a 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/roles/essentials_with_endpoint.roles.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/roles/essentials_with_endpoint.roles.cy.ts @@ -7,7 +7,7 @@ import type { CyIndexEndpointHosts } from '../../../tasks/index_endpoint_hosts'; import { indexEndpointHosts } from '../../../tasks/index_endpoint_hosts'; -import { loginServerless, ServerlessUser } from '../../../tasks/login_serverless'; +import { login, ROLE } from '../../../tasks/login'; import type { EndpointArtifactPageId } from '../../../screens'; import { getNoPrivilegesPage, @@ -55,12 +55,12 @@ describe( }); // roles `t1_analyst` and `t2_analyst` are the same as far as endpoint access - (['t1_analyst', `t2_analyst`] as ServerlessUser[]).forEach((roleName) => { + (['t1_analyst', `t2_analyst`] as ROLE[]).forEach((roleName) => { describe(`for role: ${roleName}`, () => { const deniedPages = allPages.filter((page) => page.id !== 'endpointList'); beforeEach(() => { - loginServerless(roleName); + login(roleName); }); it('should have READ access to Endpoint list page', () => { @@ -89,7 +89,7 @@ describe( ]; beforeEach(() => { - loginServerless(ServerlessUser.T3_ANALYST); + login(ROLE.t3_analyst); }); it('should have access to Endpoint list page', () => { @@ -128,7 +128,7 @@ describe( const deniedPages = allPages.filter(({ id }) => id !== 'blocklist' && id !== 'endpointList'); beforeEach(() => { - loginServerless(ServerlessUser.THREAT_INTELLIGENCE_ANALYST); + login(ROLE.threat_intelligence_analyst); }); it('should have access to Endpoint list page', () => { @@ -163,7 +163,7 @@ describe( ]; beforeEach(() => { - loginServerless(ServerlessUser.RULE_AUTHOR); + login(ROLE.rule_author); }); for (const { id, title } of artifactPagesFullAccess) { @@ -207,7 +207,7 @@ describe( const grantedAccessPages = [pageById.endpointList, pageById.policyList]; beforeEach(() => { - loginServerless(ServerlessUser.SOC_MANAGER); + login(ROLE.soc_manager); }); for (const { id, title } of artifactPagesFullAccess) { @@ -238,11 +238,7 @@ describe( // Endpoint Operations Manager, Endpoint Policy Manager and Platform Engineer currently have the same level of access ( - [ - 'platform_engineer', - `endpoint_operations_analyst`, - 'endpoint_policy_manager', - ] as ServerlessUser[] + ['platform_engineer', `endpoint_operations_analyst`, 'endpoint_policy_manager'] as ROLE[] ).forEach((roleName) => { describe(`for role: ${roleName}`, () => { const artifactPagesFullAccess = [ @@ -253,7 +249,7 @@ describe( const grantedAccessPages = [pageById.endpointList, pageById.policyList]; beforeEach(() => { - loginServerless(roleName); + login(roleName); }); for (const { id, title } of artifactPagesFullAccess) { diff --git a/x-pack/plugins/security_solution/public/management/cypress/fixtures/role_with_artifact_read_privilege.ts b/x-pack/plugins/security_solution/public/management/cypress/fixtures/role_with_artifact_read_privilege.ts new file mode 100644 index 0000000000000..247b491f04632 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/cypress/fixtures/role_with_artifact_read_privilege.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 { getEndpointSecurityPolicyManager } from '../../../../scripts/endpoint/common/roles_users'; + +export const getRoleWithArtifactReadPrivilege = (privilegePrefix: string) => { + const endpointSecurityPolicyManagerRole = getEndpointSecurityPolicyManager(); + + return { + ...endpointSecurityPolicyManagerRole, + kibana: [ + { + ...endpointSecurityPolicyManagerRole.kibana[0], + feature: { + ...endpointSecurityPolicyManagerRole.kibana[0].feature, + siem: [ + ...endpointSecurityPolicyManagerRole.kibana[0].feature.siem.filter( + (privilege) => privilege !== `${privilegePrefix}all` + ), + `${privilegePrefix}read`, + ], + }, + }, + ], + }; +}; diff --git a/x-pack/plugins/security_solution/public/management/cypress/support/data_loaders.ts b/x-pack/plugins/security_solution/public/management/cypress/support/data_loaders.ts index 4d8164391cb11..93614b6dbb86d 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/support/data_loaders.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/support/data_loaders.ts @@ -9,6 +9,14 @@ import type { CasePostRequest } from '@kbn/cases-plugin/common'; import execa from 'execa'; +import type { KbnClient } from '@kbn/test'; +import type { ToolingLog } from '@kbn/tooling-log'; +import type { KibanaKnownUserAccounts } from '../common/constants'; +import { KIBANA_KNOWN_DEFAULT_ACCOUNTS } from '../common/constants'; +import type { EndpointSecurityRoleNames } from '../../../../scripts/endpoint/common/roles_users'; +import { SECURITY_SERVERLESS_ROLE_NAMES } from '../../../../scripts/endpoint/common/roles_users'; +import type { LoadedRoleAndUser } from '../../../../scripts/endpoint/common/role_and_user_loader'; +import { EndpointSecurityTestRolesLoader } from '../../../../scripts/endpoint/common/role_and_user_loader'; import { startRuntimeServices } from '../../../../scripts/endpoint/endpoint_agent_runner/runtime'; import { runFleetServerIfNeeded } from '../../../../scripts/endpoint/endpoint_agent_runner/fleet_server'; import { @@ -22,39 +30,89 @@ import type { CreateAndEnrollEndpointHostOptions, CreateAndEnrollEndpointHostResponse, } from '../../../../scripts/endpoint/common/endpoint_host_services'; +import { + createAndEnrollEndpointHost, + destroyEndpointHost, + startEndpointHost, + stopEndpointHost, + VAGRANT_CWD, +} from '../../../../scripts/endpoint/common/endpoint_host_services'; import type { IndexedEndpointPolicyResponse } from '../../../../common/endpoint/data_loaders/index_endpoint_policy_response'; import { deleteIndexedEndpointPolicyResponse, indexEndpointPolicyResponse, } from '../../../../common/endpoint/data_loaders/index_endpoint_policy_response'; import type { ActionDetails, HostPolicyResponse } from '../../../../common/endpoint/types'; -import type { IndexEndpointHostsCyTaskOptions } from '../types'; import type { - IndexedEndpointRuleAlerts, + IndexEndpointHostsCyTaskOptions, + LoadUserAndRoleCyTaskOptions, + CreateUserAndRoleCyTaskOptions, +} from '../types'; +import type { DeletedIndexedEndpointRuleAlerts, + IndexedEndpointRuleAlerts, +} from '../../../../common/endpoint/data_loaders/index_endpoint_rule_alerts'; +import { + deleteIndexedEndpointRuleAlerts, + indexEndpointRuleAlerts, } from '../../../../common/endpoint/data_loaders/index_endpoint_rule_alerts'; import type { IndexedHostsAndAlertsResponse } from '../../../../common/endpoint/index_data'; +import { deleteIndexedHostsAndAlerts } from '../../../../common/endpoint/index_data'; import type { IndexedCase } from '../../../../common/endpoint/data_loaders/index_case'; +import { deleteIndexedCase, indexCase } from '../../../../common/endpoint/data_loaders/index_case'; import { createRuntimeServices } from '../../../../scripts/endpoint/common/stack_services'; import type { IndexedFleetEndpointPolicyResponse } from '../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy'; import { - indexFleetEndpointPolicy, deleteIndexedFleetEndpointPolicies, + indexFleetEndpointPolicy, } from '../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy'; -import { deleteIndexedCase, indexCase } from '../../../../common/endpoint/data_loaders/index_case'; import { cyLoadEndpointDataHandler } from './plugin_handlers/endpoint_data_loader'; -import { deleteIndexedHostsAndAlerts } from '../../../../common/endpoint/index_data'; -import { - deleteIndexedEndpointRuleAlerts, - indexEndpointRuleAlerts, -} from '../../../../common/endpoint/data_loaders/index_endpoint_rule_alerts'; -import { - startEndpointHost, - createAndEnrollEndpointHost, - destroyEndpointHost, - stopEndpointHost, - VAGRANT_CWD, -} from '../../../../scripts/endpoint/common/endpoint_host_services'; + +/** + * Test Role/User loader for cypress. Checks to see if running in serverless and handles it as appropriate + */ +class TestRoleAndUserLoader extends EndpointSecurityTestRolesLoader { + constructor( + protected readonly kbnClient: KbnClient, + protected readonly logger: ToolingLog, + private readonly isServerless: boolean + ) { + super(kbnClient, logger); + } + + async load( + name: EndpointSecurityRoleNames | KibanaKnownUserAccounts + ): Promise { + // If its a known system account, then just exit here and use the default `changeme` password + if (KIBANA_KNOWN_DEFAULT_ACCOUNTS[name as KibanaKnownUserAccounts]) { + return { + role: name, + username: name, + password: 'changeme', + }; + } + + if (this.isServerless) { + // If the username is not one that we support in serverless, then throw an error. + if (!SECURITY_SERVERLESS_ROLE_NAMES[name as keyof typeof SECURITY_SERVERLESS_ROLE_NAMES]) { + throw new Error( + `username [${name}] is not valid when running in serverless. Valid values are: ${Object.keys( + SECURITY_SERVERLESS_ROLE_NAMES + ).join(', ')}` + ); + } + + // Roles/users for serverless will be already present in the env, so just return the defaults creds + return { + role: name, + username: name, + password: 'changeme', + }; + } + + return super.load(name as EndpointSecurityRoleNames); + } +} /** * Cypress plugin for adding data loading related `task`s @@ -68,7 +126,8 @@ export const dataLoaders = ( on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions ): void => { - // FIXME: investigate if we can create a `ToolingLog` that writes output to cypress and pass that to the stack services + // Env. variable is set by `cypress_serverless.config.ts` + const isServerless = config.env.IS_SERVERLESS; const stackServicesPromise = createRuntimeServices({ kibanaUrl: config.env.KIBANA_URL, @@ -81,6 +140,12 @@ export const dataLoaders = ( asSuperuser: true, }); + const roleAndUserLoaderPromise: Promise = stackServicesPromise.then( + ({ kbnClient, log }) => { + return new TestRoleAndUserLoader(kbnClient, log, isServerless); + } + ); + on('task', { indexFleetEndpointPolicy: async ({ policyName, @@ -201,6 +266,23 @@ export const dataLoaders = ( const { esClient } = await stackServicesPromise; return deleteAllEndpointData(esClient, endpointAgentIds); }, + + /** + * Loads a user/role into Kibana. Used from `login()` task. + * @param name + */ + loadUserAndRole: async ({ name }: LoadUserAndRoleCyTaskOptions): Promise => { + return (await roleAndUserLoaderPromise).load(name); + }, + + /** + * Creates a new Role/User + */ + createUserAndRole: async ({ + role, + }: CreateUserAndRoleCyTaskOptions): Promise => { + return (await roleAndUserLoaderPromise).create(role); + }, }); }; diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/login.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/login.ts index 58eba62a72f82..8ac78b508d084 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/login.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/login.ts @@ -5,242 +5,107 @@ * 2.0. */ -import * as yaml from 'js-yaml'; -import type { Role } from '@kbn/security-plugin/common'; import type { LoginState } from '@kbn/security-plugin/common/login_state'; -import { getWithResponseActionsRole } from '../../../../scripts/endpoint/common/roles_users/with_response_actions_role'; -import { getNoResponseActionsRole } from '../../../../scripts/endpoint/common/roles_users/without_response_actions_role'; -import { request } from './common'; -import { getT1Analyst } from '../../../../scripts/endpoint/common/roles_users/t1_analyst'; -import { getT2Analyst } from '../../../../scripts/endpoint/common/roles_users/t2_analyst'; -import { getHunter } from '../../../../scripts/endpoint/common/roles_users/hunter'; -import { getThreatIntelligenceAnalyst } from '../../../../scripts/endpoint/common/roles_users/threat_intelligence_analyst'; -import { getSocManager } from '../../../../scripts/endpoint/common/roles_users/soc_manager'; -import { getPlatformEngineer } from '../../../../scripts/endpoint/common/roles_users/platform_engineer'; -import { getEndpointOperationsAnalyst } from '../../../../scripts/endpoint/common/roles_users/endpoint_operations_analyst'; -import { - getEndpointSecurityPolicyManagementReadRole, - getEndpointSecurityPolicyManager, -} from '../../../../scripts/endpoint/common/roles_users/endpoint_security_policy_manager'; -import { getDetectionsEngineer } from '../../../../scripts/endpoint/common/roles_users/detections_engineer'; - -export enum ROLE { - t1_analyst = 't1Analyst', - t2_analyst = 't2Analyst', - analyst_hunter = 'hunter', - threat_intelligence_analyst = 'threatIntelligenceAnalyst', - detections_engineer = 'detectionsEngineer', - soc_manager = 'socManager', - platform_engineer = 'platformEngineer', - endpoint_operations_analyst = 'endpointOperationsAnalyst', - endpoint_security_policy_manager = 'endpointSecurityPolicyManager', - endpoint_response_actions_access = 'endpointResponseActionsAccess', - endpoint_response_actions_no_access = 'endpointResponseActionsNoAccess', - endpoint_security_policy_management_read = 'endpointSecurityPolicyManagementRead', +import type { Role } from '@kbn/security-plugin/common'; +import { ENDPOINT_SECURITY_ROLE_NAMES } from '../../../../scripts/endpoint/common/roles_users'; +import type { SecurityTestUser } from '../common/constants'; +import { COMMON_API_HEADERS, request } from './common'; + +export const ROLE = Object.freeze>({ + ...ENDPOINT_SECURITY_ROLE_NAMES, + elastic: 'elastic', + elastic_serverless: 'elastic_serverless', + system_indices_superuser: 'system_indices_superuser', +}); + +interface CyLoginTask { + (user?: SecurityTestUser): ReturnType; + + /** + * Login using any username/password + * @param username + * @param password + */ + with(username: string, password: string): ReturnType; + + /** + * Creates the provided role in kibana/ES along with a respective user (same name as role) + * and then login with this new user + * @param role + */ + withCustomRole(role: Role): ReturnType; } -export const rolesMapping: { [key in ROLE]: Omit } = { - t1Analyst: getT1Analyst(), - t2Analyst: getT2Analyst(), - hunter: getHunter(), - threatIntelligenceAnalyst: getThreatIntelligenceAnalyst(), - socManager: getSocManager(), - platformEngineer: getPlatformEngineer(), - endpointOperationsAnalyst: getEndpointOperationsAnalyst(), - endpointSecurityPolicyManager: getEndpointSecurityPolicyManager(), - detectionsEngineer: getDetectionsEngineer(), - endpointResponseActionsAccess: getWithResponseActionsRole(), - endpointResponseActionsNoAccess: getNoResponseActionsRole(), - endpointSecurityPolicyManagementRead: getEndpointSecurityPolicyManagementReadRole(), -}; -/** - * Credentials in the `kibana.dev.yml` config file will be used to authenticate - * with Kibana when credentials are not provided via environment variables - */ -const KIBANA_DEV_YML_PATH = '../../../config/kibana.dev.yml'; - -/** - * The configuration path in `kibana.dev.yml` to the username to be used when - * authenticating with Kibana. - */ -const ELASTICSEARCH_USERNAME_CONFIG_PATH = 'config.elasticsearch.username'; - -/** - * The configuration path in `kibana.dev.yml` to the password to be used when - * authenticating with Kibana. - */ -const ELASTICSEARCH_PASSWORD_CONFIG_PATH = 'config.elasticsearch.password'; - -/** - * The `CYPRESS_ELASTICSEARCH_USERNAME` environment variable specifies the - * username to be used when authenticating with Kibana - */ -const ELASTICSEARCH_USERNAME = 'ELASTICSEARCH_USERNAME'; - /** - * The `CYPRESS_ELASTICSEARCH_PASSWORD` environment variable specifies the - * username to be used when authenticating with Kibana + * Login to Kibana using API (not login page). + * By default, user will be logged in using `KIBANA_USERNAME` and `KIBANA_PASSWORD` retrieved from + * the cypress `env` + * + * @param user */ -const ELASTICSEARCH_PASSWORD = 'ELASTICSEARCH_PASSWORD'; - -const KIBANA_USERNAME = 'KIBANA_USERNAME'; -const KIBANA_PASSWORD = 'KIBANA_PASSWORD'; +export const login: CyLoginTask = ( + // FIXME:PT default user to `soc_manager` + user?: SecurityTestUser +): ReturnType => { + let username = Cypress.env('KIBANA_USERNAME'); + let password = Cypress.env('KIBANA_PASSWORD'); + + if (user) { + return cy.task('loadUserAndRole', { name: user }).then((loadedUser) => { + username = loadedUser.username; + password = loadedUser.password; + + return sendApiLoginRequest(username, password); + }); + } else { + return sendApiLoginRequest(username, password); + } +}; -export const createCustomRoleAndUser = (role: string, rolePrivileges: Omit) => { - // post the role - request({ - method: 'PUT', - url: `/api/security/role/${role}`, - body: rolePrivileges, - }); +login.with = (username: string, password: string): ReturnType => { + return sendApiLoginRequest(username, password); +}; - // post the user associated with the role to elasticsearch - request({ - method: 'POST', - url: `/internal/security/users/${role}`, - body: { - username: role, - password: Cypress.env(ELASTICSEARCH_PASSWORD), - roles: [role], - }, +login.withCustomRole = (role: Role): ReturnType => { + return cy.task('createUserAndRole', { role }).then(({ username, password }) => { + return sendApiLoginRequest(username, password); }); }; -const loginWithUsernameAndPassword = (username: string, password: string) => { +/** + * Send login via API + * @param username + * @param password + * + * @private + */ +const sendApiLoginRequest = ( + username: string, + password: string +): Cypress.Chainable<{ username: string; password: string }> => { const baseUrl = Cypress.config().baseUrl; - if (!baseUrl) { - throw Error(`Cypress config baseUrl not set!`); - } + const loginUrl = `${baseUrl}/internal/security/login`; + const headers = { ...COMMON_API_HEADERS }; + + cy.log(`Authenticating [${username}] via ${loginUrl}`); - // Programmatically authenticate without interacting with the Kibana login page. - const headers = { 'kbn-xsrf': 'cypress-creds' }; - request({ headers, url: `${baseUrl}/internal/security/login_state` }).then( - (loginState) => { + return request({ headers, url: `${baseUrl}/internal/security/login_state` }) + .then((loginState) => { const basicProvider = loginState.body.selector.providers.find( (provider) => provider.type === 'basic' ); + return request({ - url: `${baseUrl}/internal/security/login`, + url: loginUrl, method: 'POST', headers, body: { - providerType: basicProvider.type, - providerName: basicProvider.name, + providerType: basicProvider?.type, + providerName: basicProvider?.name, currentURL: '/', params: { username, password }, }, }); - } - ); -}; - -export const loginWithRole = (role: ROLE) => { - loginWithCustomRole(role, rolesMapping[role]); -}; - -export const loginWithCustomRole = (role: string, rolePrivileges: Omit) => { - createCustomRoleAndUser(role, rolePrivileges); - - cy.log(`origin: ${Cypress.config().baseUrl}`); - - loginWithUsernameAndPassword(role, Cypress.env(ELASTICSEARCH_PASSWORD)); -}; - -/** - * Authenticates with Kibana using, if specified, credentials specified by - * environment variables. The credentials in `kibana.dev.yml` will be used - * for authentication when the environment variables are unset. - * - * To speed the execution of tests, prefer this non-interactive authentication, - * which is faster than authentication via Kibana's interactive login page. - */ -export const login = (role?: ROLE) => { - if (role != null) { - loginWithRole(role); - } else if (credentialsProvidedByEnvironment()) { - loginViaEnvironmentCredentials(); - } else { - loginViaConfig(); - } -}; - -/** - * Returns `true` if the credentials used to login to Kibana are provided - * via environment variables - */ -const credentialsProvidedByEnvironment = (): boolean => - (Cypress.env(KIBANA_USERNAME) != null && Cypress.env(KIBANA_PASSWORD) != null) || - (Cypress.env(ELASTICSEARCH_USERNAME) != null && Cypress.env(ELASTICSEARCH_PASSWORD) != null); - -/** - * Authenticates with Kibana by reading credentials from the - * `CYPRESS_ELASTICSEARCH_USERNAME` and `CYPRESS_ELASTICSEARCH_PASSWORD` - * environment variables, and POSTing the username and password directly to - * Kibana's `/internal/security/login` endpoint, bypassing the login page (for speed). - */ -const loginViaEnvironmentCredentials = () => { - let username: string; - let password: string; - let usernameEnvVar: string; - let passwordEnvVar: string; - - if (Cypress.env(KIBANA_USERNAME) && Cypress.env(KIBANA_PASSWORD)) { - username = Cypress.env(KIBANA_USERNAME); - password = Cypress.env(KIBANA_PASSWORD); - usernameEnvVar = KIBANA_USERNAME; - passwordEnvVar = KIBANA_PASSWORD; - } else { - username = Cypress.env(ELASTICSEARCH_USERNAME); - password = Cypress.env(ELASTICSEARCH_PASSWORD); - usernameEnvVar = ELASTICSEARCH_USERNAME; - passwordEnvVar = ELASTICSEARCH_PASSWORD; - } - - cy.log( - `Authenticating user [${username}] retrieved via environment credentials from the \`CYPRESS_${usernameEnvVar}\` and \`CYPRESS_${passwordEnvVar}\` environment variables` - ); - - loginWithUsernameAndPassword(username, password); -}; - -/** - * Authenticates with Kibana by reading credentials from the - * `kibana.dev.yml` file and POSTing the username and password directly to - * Kibana's `/internal/security/login` endpoint, bypassing the login page (for speed). - */ -const loginViaConfig = () => { - cy.log( - `Authenticating via config credentials \`${ELASTICSEARCH_USERNAME_CONFIG_PATH}\` and \`${ELASTICSEARCH_PASSWORD_CONFIG_PATH}\` from \`${KIBANA_DEV_YML_PATH}\`` - ); - - // read the login details from `kibana.dev.yaml` - cy.readFile(KIBANA_DEV_YML_PATH).then((kibanaDevYml) => { - const config = yaml.safeLoad(kibanaDevYml); - loginWithUsernameAndPassword( - Cypress.env(ELASTICSEARCH_USERNAME), - config.elasticsearch.password - ); - }); -}; - -export const getRoleWithArtifactReadPrivilege = (privilegePrefix: string) => { - const endpointSecurityPolicyManagerRole = getEndpointSecurityPolicyManager(); - - return { - ...endpointSecurityPolicyManagerRole, - kibana: [ - { - ...endpointSecurityPolicyManagerRole.kibana[0], - feature: { - ...endpointSecurityPolicyManagerRole.kibana[0].feature, - siem: [ - ...endpointSecurityPolicyManagerRole.kibana[0].feature.siem.filter( - (privilege) => privilege !== `${privilegePrefix}all` - ), - `${privilegePrefix}read`, - ], - }, - }, - ], - }; + }) + .then(() => ({ username, password })); }; diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/login_serverless.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/login_serverless.ts deleted file mode 100644 index 533a17663e16b..0000000000000 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/login_serverless.ts +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { LoginState } from '@kbn/security-plugin/common/login_state'; -import { COMMON_API_HEADERS, request } from './common'; - -export enum ServerlessUser { - T1_ANALYST = 't1_analyst', - T2_ANALYST = 't2_analyst', - T3_ANALYST = 't3_analyst', - THREAT_INTELLIGENCE_ANALYST = 'threat_intelligence_analyst', - RULE_AUTHOR = 'rule_author', - SOC_MANAGER = 'soc_manager', - DETECTIONS_ADMIN = 'detections_admin', - PLATFORM_ENGINEER = 'platform_engineer', - ENDPOINT_OPERATIONS_ANALYST = 'endpoint_operations_analyst', - ENDPOINT_POLICY_MANAGER = 'endpoint_policy_manager', -} - -/** - * Send login via API - * @param username - * @param password - * - * @private - */ -const sendApiLoginRequest = ( - username: string, - password: string -): Cypress.Chainable<{ username: string; password: string }> => { - const baseUrl = Cypress.config().baseUrl; - const headers = { ...COMMON_API_HEADERS }; - - cy.log(`Authenticating [${username}] via ${baseUrl}`); - - return request({ headers, url: `${baseUrl}/internal/security/login_state` }) - .then((loginState) => { - const basicProvider = loginState.body.selector.providers.find( - (provider) => provider.type === 'basic' - ); - - return request({ - url: `${baseUrl}/internal/security/login`, - method: 'POST', - headers, - body: { - providerType: basicProvider?.type, - providerName: basicProvider?.name, - currentURL: '/', - params: { username, password }, - }, - }); - }) - .then(() => ({ username, password })); -}; - -interface CyLoginTask { - (user?: ServerlessUser | 'elastic'): ReturnType; - - /** - * Login using any username/password - * @param username - * @param password - */ - with(username: string, password: string): ReturnType; -} - -/** - * Login to Kibana using API (not login page). By default, user will be logged in using - * the username and password defined via `KIBANA_USERNAME` and `KIBANA_PASSWORD` cypress env - * variables. - * @param user Defaults to `soc_manager` - */ -export const loginServerless: CyLoginTask = ( - user: ServerlessUser | 'elastic' = ServerlessUser.SOC_MANAGER -): ReturnType => { - const username = Cypress.env('KIBANA_USERNAME'); - const password = Cypress.env('KIBANA_PASSWORD'); - - if (user && user !== 'elastic') { - throw new Error('Serverless usernames not yet implemented'); - - // return cy.task('loadUserAndRole', { name: user }).then((loadedUser) => { - // username = loadedUser.username; - // password = loadedUser.password; - // - // return sendApiLoginRequest(username, password); - // }); - } else { - return sendApiLoginRequest(username, password); - } -}; - -loginServerless.with = ( - username: string, - password: string -): ReturnType => { - return sendApiLoginRequest(username, password); -}; diff --git a/x-pack/plugins/security_solution/public/management/cypress/tsconfig.json b/x-pack/plugins/security_solution/public/management/cypress/tsconfig.json index 4d7fe47ec2d23..94d50ffe7f62a 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tsconfig.json +++ b/x-pack/plugins/security_solution/public/management/cypress/tsconfig.json @@ -32,5 +32,6 @@ "@kbn/test", "@kbn/repo-info", "@kbn/data-views-plugin", + "@kbn/tooling-log", ] } diff --git a/x-pack/plugins/security_solution/public/management/cypress/types.ts b/x-pack/plugins/security_solution/public/management/cypress/types.ts index fecaa33a6a70a..aee97723c7d51 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/types.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/types.ts @@ -7,8 +7,10 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +import type { Role } from '@kbn/security-plugin/common'; import type { ActionDetails } from '../../../common/endpoint/types'; import type { CyLoadEndpointDataOptions } from './support/plugin_handlers/endpoint_data_loader'; +import type { SecurityTestUser } from './common/constants'; type PossibleChainable = | Cypress.Chainable @@ -56,3 +58,11 @@ export interface HostActionResponse { state: { state?: 'success' | 'failure' }; }; } + +export interface LoadUserAndRoleCyTaskOptions { + name: SecurityTestUser; +} + +export interface CreateUserAndRoleCyTaskOptions { + role: Role; +} diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/constants.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/constants.ts index 1d2b3d5f47784..4a8b2daca2af4 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/constants.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/constants.ts @@ -10,3 +10,8 @@ export const HORIZONTAL_LINE = '-'.repeat(80); export const ENDPOINT_EVENTS_INDEX = 'logs-endpoint.events.process-default'; export const ENDPOINT_ALERTS_INDEX = 'logs-endpoint.alerts-default'; + +export const COMMON_API_HEADERS = Object.freeze({ + 'kbn-xsrf': 'security-solution', + 'x-elastic-internal-origin': 'security-solution', +}); diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/role_and_user_loader.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/role_and_user_loader.ts new file mode 100644 index 0000000000000..f8c51d5255018 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/role_and_user_loader.ts @@ -0,0 +1,175 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* eslint-disable max-classes-per-file */ + +import type { KbnClient } from '@kbn/test'; +import type { Role } from '@kbn/security-plugin/common'; +import type { ToolingLog } from '@kbn/tooling-log'; +import { inspect } from 'util'; +import type { AxiosError } from 'axios'; +import type { EndpointSecurityRoleDefinitions } from './roles_users'; +import { getAllEndpointSecurityRoles } from './roles_users'; +import { catchAxiosErrorFormatAndThrow } from './format_axios_error'; +import { COMMON_API_HEADERS } from './constants'; + +const ignoreHttp409Error = (error: AxiosError) => { + if (error?.response?.status === 409) { + return; + } + + throw error; +}; + +export interface LoadedRoleAndUser { + role: string; + username: string; + password: string; +} + +export interface RoleAndUserLoaderInterface = Record> { + /** + * Loads the requested Role into kibana and then creates a user by the same role name that is + * assigned to the given role + * @param name + */ + load(name: keyof R): Promise; + + /** + * Loads all roles/users + */ + loadAll(): Promise>; + + /** + * Creates a new Role in kibana along with a user (by the same name as the Role name) + * that is assigned to the given role + * @param role + */ + create(role: Role): Promise; +} + +/** + * A generic class for loading roles and creating associated user into kibana + */ +export class RoleAndUserLoader = Record> + implements RoleAndUserLoaderInterface +{ + protected readonly logPromiseError: (error: Error) => never; + + constructor( + protected readonly kbnClient: KbnClient, + protected readonly logger: ToolingLog, + protected readonly roles: R + ) { + this.logPromiseError = (error) => { + this.logger.error(inspect(error, { depth: 5 })); + throw error; + }; + } + + async load(name: keyof R): Promise { + const role = this.roles[name]; + + if (!role) { + throw new Error( + `Unknown role/user: [${String(name)}]. Valid values are: [${Object.keys(this.roles).join( + ', ' + )}]` + ); + } + + return this.create(role); + } + + async loadAll(): Promise> { + const response = {} as Record; + + for (const [name, role] of Object.entries(this.roles)) { + response[name as keyof R] = await this.create(role); + } + + return response; + } + + public async create(role: Role): Promise { + const roleName = role.name; + + await this.createRole(role); + await this.createUser(roleName, 'changeme', [roleName]); + + return { + role: roleName, + username: roleName, + password: 'changeme', + }; + } + + protected async createRole(role: Role): Promise { + const { name: roleName, ...roleDefinition } = role; + + this.logger.debug(`creating role:`, roleDefinition); + + await this.kbnClient + .request({ + method: 'PUT', + path: `/api/security/role/${roleName}`, + headers: { + ...COMMON_API_HEADERS, + }, + body: roleDefinition, + }) + .then((response) => { + this.logger.debug(`Role [${roleName}] created/updated`, response?.data); + return response; + }) + .catch(ignoreHttp409Error) + .catch(catchAxiosErrorFormatAndThrow) + .catch(this.logPromiseError); + } + + protected async createUser( + username: string, + password: string, + roles: string[] = [] + ): Promise { + const user = { + username, + password, + roles, + full_name: username, + email: '', + }; + + this.logger.debug(`creating user:`, user); + + await this.kbnClient + .request({ + method: 'POST', + path: `/internal/security/users/${username}`, + headers: { + ...COMMON_API_HEADERS, + }, + body: user, + }) + .then((response) => { + this.logger.debug(`User [${username}] created/updated`, response?.data); + return response; + }) + .catch(ignoreHttp409Error) + .catch(catchAxiosErrorFormatAndThrow) + .catch(this.logPromiseError); + } +} + +/** + * Role and user loader for Endpoint security dev/testing + */ +export class EndpointSecurityTestRolesLoader extends RoleAndUserLoader { + constructor(protected readonly kbnClient: KbnClient, protected readonly logger: ToolingLog) { + super(kbnClient, logger, getAllEndpointSecurityRoles()); + } +} diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/index.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/index.ts new file mode 100644 index 0000000000000..b035f55bf1589 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/index.ts @@ -0,0 +1,139 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { Role } from '@kbn/security-plugin/common'; +import { getRuleAuthor } from './rule_author'; +import { getT3Analyst } from './t3_analyst'; +import { getT1Analyst } from './t1_analyst'; +import { getT2Analyst } from './t2_analyst'; +import { getHunter } from './hunter'; +import { getThreatIntelligenceAnalyst } from './threat_intelligence_analyst'; +import { getSocManager } from './soc_manager'; +import { getPlatformEngineer } from './platform_engineer'; +import { getEndpointOperationsAnalyst } from './endpoint_operations_analyst'; +import { + getEndpointSecurityPolicyManagementReadRole, + getEndpointSecurityPolicyManager, +} from './endpoint_security_policy_manager'; +import { getDetectionsEngineer } from './detections_engineer'; +import { getWithResponseActionsRole } from './with_response_actions_role'; +import { getNoResponseActionsRole } from './without_response_actions_role'; + +export * from './with_response_actions_role'; +export * from './without_response_actions_role'; +export * from './t1_analyst'; +export * from './t2_analyst'; +export * from './t3_analyst'; +export * from './hunter'; +export * from './threat_intelligence_analyst'; +export * from './soc_manager'; +export * from './platform_engineer'; +export * from './endpoint_operations_analyst'; +export * from './endpoint_security_policy_manager'; +export * from './detections_engineer'; + +export type EndpointSecurityRoleNames = keyof typeof ENDPOINT_SECURITY_ROLE_NAMES; + +export type EndpointSecurityRoleDefinitions = Record; + +/** + * Security Solution set of roles that are loaded and used in serverless deployments. + * The source of these role definitions is under `project-controller` at: + * + * @see https://github.com/elastic/project-controller/blob/main/internal/project/security/config/roles.yml + * + * The role definition spreadsheet can be found here: + * + * @see https://docs.google.com/spreadsheets/d/16aGow187AunLCBFZLlbVyS81iQNuMpNxd96LOerWj4c/edit#gid=1936689222 + */ +export const SECURITY_SERVERLESS_ROLE_NAMES = Object.freeze({ + t1_analyst: 't1_analyst', + t2_analyst: 't2_analyst', + t3_analyst: 't3_analyst', + threat_intelligence_analyst: 'threat_intelligence_analyst', + rule_author: 'rule_author', + soc_manager: 'soc_manager', + detections_admin: 'detections_admin', + platform_engineer: 'platform_engineer', + endpoint_operations_analyst: 'endpoint_operations_analyst', + endpoint_policy_manager: 'endpoint_policy_manager', +}); + +export const ENDPOINT_SECURITY_ROLE_NAMES = Object.freeze({ + // -------------------------------------- + // Set of roles used in serverless + ...SECURITY_SERVERLESS_ROLE_NAMES, + + // -------------------------------------- + // Other roles used for testing + hunter: 'hunter', + endpoint_response_actions_access: 'endpoint_response_actions_access', + endpoint_response_actions_no_access: 'endpoint_response_actions_no_access', + endpoint_security_policy_management_read: 'endpoint_security_policy_management_read', +}); + +export const getAllEndpointSecurityRoles = (): EndpointSecurityRoleDefinitions => { + return { + t1_analyst: { + ...getT1Analyst(), + name: 't1_analyst', + }, + t2_analyst: { + ...getT2Analyst(), + name: 't2_analyst', + }, + t3_analyst: { + ...getT3Analyst(), + name: 't3_analyst', + }, + threat_intelligence_analyst: { + ...getThreatIntelligenceAnalyst(), + name: 'threat_intelligence_analyst', + }, + rule_author: { + ...getRuleAuthor(), + name: 'rule_author', + }, + soc_manager: { + ...getSocManager(), + name: 'soc_manager', + }, + detections_admin: { + ...getDetectionsEngineer(), + name: 'detections_admin', + }, + platform_engineer: { + ...getPlatformEngineer(), + name: 'platform_engineer', + }, + endpoint_operations_analyst: { + ...getEndpointOperationsAnalyst(), + name: 'endpoint_operations_analyst', + }, + endpoint_policy_manager: { + ...getEndpointSecurityPolicyManager(), + name: 'endpoint_policy_manager', + }, + + hunter: { + ...getHunter(), + name: 'hunter', + }, + endpoint_response_actions_access: { + ...getWithResponseActionsRole(), + name: 'endpoint_response_actions_access', + }, + endpoint_response_actions_no_access: { + ...getNoResponseActionsRole(), + name: 'endpoint_response_actions_no_access', + }, + endpoint_security_policy_management_read: { + ...getEndpointSecurityPolicyManagementReadRole(), + name: 'endpoint_security_policy_management_read', + }, + }; +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/rule_author.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/rule_author.ts new file mode 100644 index 0000000000000..f957fe8947c5d --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/rule_author.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Role } from '@kbn/security-plugin/common'; +import { getNoResponseActionsRole } from './without_response_actions_role'; + +export const getRuleAuthor: () => Omit = () => { + const noResponseActionsRole = getNoResponseActionsRole(); + return { + ...noResponseActionsRole, + kibana: [ + { + ...noResponseActionsRole.kibana[0], + feature: { + ...noResponseActionsRole.kibana[0].feature, + siem: [ + 'all', + 'read_alerts', + 'crud_alerts', + 'policy_management_all', + 'endpoint_list_all', + 'trusted_applications_all', + 'event_filters_all', + 'host_isolation_exceptions_read', + 'blocklist_all', + 'actions_log_management_read', + ], + }, + }, + ], + }; +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/t3_analyst.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/t3_analyst.ts new file mode 100644 index 0000000000000..304c4e6d744ee --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/t3_analyst.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 type { Role } from '@kbn/security-plugin/common'; +import { getNoResponseActionsRole } from './without_response_actions_role'; + +export const getT3Analyst: () => Omit = () => { + const noResponseActionsRole = getNoResponseActionsRole(); + return { + ...noResponseActionsRole, + kibana: [ + { + ...noResponseActionsRole.kibana[0], + feature: { + ...noResponseActionsRole.kibana[0].feature, + siem: [ + 'all', + 'read_alerts', + 'crud_alerts', + 'endpoint_list_all', + 'trusted_applications_all', + 'event_filters_all', + 'host_isolation_exceptions_all', + 'blocklist_all', + 'policy_management_read', + 'host_isolation_all', + 'process_operations_all', + 'actions_log_management_all', + 'file_operations_all', + ], + }, + }, + ], + }; +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/resolver_generator_script.ts b/x-pack/plugins/security_solution/scripts/endpoint/resolver_generator_script.ts index c1c38dcf8b30a..330bcf4589a74 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/resolver_generator_script.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/resolver_generator_script.ts @@ -14,36 +14,13 @@ import { CA_CERT_PATH } from '@kbn/dev-utils'; import { ToolingLog } from '@kbn/tooling-log'; import type { KbnClientOptions } from '@kbn/test'; import { KbnClient } from '@kbn/test'; -import type { Role } from '@kbn/security-plugin/common'; +import { EndpointSecurityTestRolesLoader } from './common/role_and_user_loader'; import { METADATA_DATASTREAM } from '../../common/endpoint/constants'; import { EndpointMetadataGenerator } from '../../common/endpoint/data_generators/endpoint_metadata_generator'; import { indexHostsAndAlerts } from '../../common/endpoint/index_data'; import { ANCESTRY_LIMIT, EndpointDocGenerator } from '../../common/endpoint/generate_data'; import { fetchStackVersion, isServerlessKibanaFlavor } from './common/stack_services'; import { ENDPOINT_ALERTS_INDEX, ENDPOINT_EVENTS_INDEX } from './common/constants'; -import { getWithResponseActionsRole } from './common/roles_users/with_response_actions_role'; -import { getNoResponseActionsRole } from './common/roles_users/without_response_actions_role'; -import { getT1Analyst } from './common/roles_users/t1_analyst'; -import { getT2Analyst } from './common/roles_users/t2_analyst'; -import { getEndpointOperationsAnalyst } from './common/roles_users/endpoint_operations_analyst'; -import { getEndpointSecurityPolicyManager } from './common/roles_users/endpoint_security_policy_manager'; -import { getHunter } from './common/roles_users/hunter'; -import { getPlatformEngineer } from './common/roles_users/platform_engineer'; -import { getSocManager } from './common/roles_users/soc_manager'; -import { getThreatIntelligenceAnalyst } from './common/roles_users/threat_intelligence_analyst'; - -const rolesMapping: { [id: string]: Omit } = { - t1Analyst: getT1Analyst(), - t2Analyst: getT2Analyst(), - hunter: getHunter(), - threatIntelligenceAnalyst: getThreatIntelligenceAnalyst(), - socManager: getSocManager(), - platformEngineer: getPlatformEngineer(), - endpointOperationsAnalyst: getEndpointOperationsAnalyst(), - endpointSecurityPolicyManager: getEndpointSecurityPolicyManager(), - withResponseActionsRole: getWithResponseActionsRole(), - noResponseActionsRole: getNoResponseActionsRole(), -}; main(); @@ -67,31 +44,6 @@ async function deleteIndices(indices: string[], client: Client) { } } -async function addRole(kbnClient: KbnClient, role: Role): Promise { - if (!role) { - console.log('No role data given'); - return; - } - - const { name, ...permissions } = role; - const path = `/api/security/role/${name}?createOnly=true`; - - // add role if doesn't exist already - try { - console.log(`Adding ${name} role`); - await kbnClient.request({ - method: 'PUT', - path, - body: permissions, - }); - - return name; - } catch (error) { - console.log(error); - handleErr(error); - } -} - interface UserInfo { username: string; password: string; @@ -422,19 +374,7 @@ async function main() { throw new Error(`Can not use '--rbacUser' option against serverless deployment`); } - // Add roles and users with response actions kibana privileges - for (const role of Object.keys(rolesMapping)) { - const addedRole = await addRole(kbnClient, { - name: role, - ...rolesMapping[role], - }); - if (addedRole) { - logger.info(`Successfully added ${role} role`); - await addUser(client, { username: role, password: 'changeme', roles: [role] }); - } else { - logger.warning(`Failed to add role, ${role}`); - } - } + await loadRbacTestUsers(kbnClient, logger); } const seed = argv.seed || Math.random().toString(); @@ -499,3 +439,12 @@ async function main() { logger.info(`Creating and indexing documents took: ${new Date().getTime() - startTime}ms`); } + +const loadRbacTestUsers = async (kbnClient: KbnClient, logger: ToolingLog): Promise => { + const loadedRoles = await new EndpointSecurityTestRolesLoader(kbnClient, logger).loadAll(); + + logger.info(`Roles and associated users loaded. Login accounts: + ${Object.values(loadedRoles) + .map(({ username, password }) => `${username} / ${password}`) + .join('\n ')}`); +}; From 077be69de1a99335ab72d710496c67835d51d75e Mon Sep 17 00:00:00 2001 From: Andrew Macri Date: Mon, 25 Sep 2023 11:55:19 -0600 Subject: [PATCH 27/45] [Security Solution] [Elastic AI Assistant] LangChain Agents and Tools integration for ES|QL query generation via ELSER (#167097) ## [Security Solution] [Elastic AI Assistant] LangChain Agents and Tools integration for ES|QL query generation via ELSER This PR integrates [LangChain](https://www.langchain.com/) [Agents](https://js.langchain.com/docs/modules/agents/) and [Tools](https://js.langchain.com/docs/modules/agents/tools/) with the [Elastic AI Assistant](https://www.elastic.co/blog/introducing-elastic-ai-assistant). These abstractions enable the LLM to dynamically choose whether or not to query, via [ELSER](https://www.elastic.co/guide/en/machine-learning/current/ml-nlp-elser.html), an [ES|QL](https://www.elastic.co/blog/elasticsearch-query-language-esql) knowledge base. Context from the knowledge base is used to generate `ES|QL` queries, or answer questions about `ES|QL`. Registration of the tool occurs in `x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts`: ```typescript const tools: Tool[] = [ new ChainTool({ name: 'esql-language-knowledge-base', description: 'Call this for knowledge on how to build an ESQL query, or answer questions about the ES|QL query language.', chain, }), ]; ``` The `tools` array above may be updated in future PRs to include, for example, an `ES|QL` query validator endpoint. ### Details The `callAgentExecutor` function in `x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts`: 1. Creates a `RetrievalQAChain` from an `ELSER` backed `ElasticsearchStore`, which serves as a knowledge base for `ES|QL`: ```typescript // ELSER backed ElasticsearchStore for Knowledge Base const esStore = new ElasticsearchStore(esClient, KNOWLEDGE_BASE_INDEX_PATTERN, logger); const chain = RetrievalQAChain.fromLLM(llm, esStore.asRetriever()); ``` 2. Registers the chain as a tool, which may be invoked by the LLM based on its description: ```typescript const tools: Tool[] = [ new ChainTool({ name: 'esql-language-knowledge-base', description: 'Call this for knowledge on how to build an ESQL query, or answer questions about the ES|QL query language.', chain, }), ]; ``` 3. Creates an Agent executor that combines the `tools` above, the `ActionsClientLlm` (an abstraction that calls `actionsClient.execute`), and memory of the previous messages in the conversation: ```typescript const executor = await initializeAgentExecutorWithOptions(tools, llm, { agentType: 'chat-conversational-react-description', memory, verbose: false, }); ``` Note: Set `verbose` above to `true` to for detailed debugging output from LangChain. 4. Calls the `executor`, kicking it off with `latestMessage`: ```typescript await executor.call({ input: latestMessage[0].content }); ``` ### Changes to `x-pack/packages/kbn-elastic-assistant` A client side change was required to the assistant, because the response returned from the agent executor is JSON. This response is parsed on the client in `x-pack/packages/kbn-elastic-assistant/impl/assistant/api.tsx`: ```typescript return assistantLangChain ? getFormattedMessageContent(result) : result; ``` Client-side parsing of the response only happens when then `assistantLangChain` feature flag is `true`. ## Desk testing Set ```typescript assistantLangChain={true} ``` in `x-pack/plugins/security_solution/public/assistant/provider.tsx` to enable this experimental feature in development environments. Also (optionally) set `verbose` to `true` in the following code in ``x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts``: ```typescript const executor = await initializeAgentExecutorWithOptions(tools, llm, { agentType: 'chat-conversational-react-description', memory, verbose: true, }); ``` After setting the feature flag and optionally enabling verbose debugging output, you may ask the assistant to generate an `ES|QL` query, per the example in the next section. ### Example output When the Elastic AI Assistant is asked: ``` From employees, I want to see the 5 earliest employees (hire_date), I want to display only the month and the year that they were hired in and their employee number (emp_no). Format the date as e.g. "September 2019". Only show the query ``` it replies: ``` Here is the query to get the employee number and the formatted hire date for the 5 earliest employees by hire_date: FROM employees | KEEP emp_no, hire_date | EVAL month_year = DATE_FORMAT(hire_date, "MMMM YYYY") | SORT hire_date | LIMIT 5 ``` Per the screenshot below: ![ESQL_query_via_langchain_agents_and_tools](https://github.com/elastic/kibana/assets/4459398/c5cc75da-f7aa-4a12-9078-ed531f3463e7) The `verbose: true` output from LangChain logged to the console reveals that the prompt sent to the LLM includes text like the following: ``` Assistant can ask the user to use tools to look up information that may be helpful in answering the users original question. The tools the human can use are:\\n\\nesql-language-knowledge-base: Call this for knowledge on how to build an ESQL query, or answer questions about the ES|QL query language. ``` along with instructions for "calling" the tool like a function. The debugging output also reveals the agent selecting the tool, and returning results from ESLR: ``` [agent/action] [1:chain:AgentExecutor] Agent selected action: { "tool": "esql-language-knowledge-base", "toolInput": "Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'.", "log": "```json\n{\n \"action\": \"esql-language-knowledge-base\",\n \"action_input\": \"Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'.\"\n}\n```" } [tool/start] [1:chain:AgentExecutor > 4:tool:ChainTool] Entering Tool run with input: "Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'." [chain/start] [1:chain:AgentExecutor > 4:tool:ChainTool > 5:chain:RetrievalQAChain] Entering Chain run with input: { "query": "Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'." } [retriever/start] [1:chain:AgentExecutor > 4:tool:ChainTool > 5:chain:RetrievalQAChain > 6:retriever:VectorStoreRetriever] Entering Retriever run with input: { "query": "Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'." } [retriever/end] [1:chain:AgentExecutor > 4:tool:ChainTool > 5:chain:RetrievalQAChain > 6:retriever:VectorStoreRetriever] [115ms] Exiting Retriever run with output: { "documents": [ { "pageContent": "[[esql-date_format]]\n=== `DATE_FORMAT`\nReturns a string representation of a date in the provided format. If no format\nis specified, the `yyyy-MM-dd'T'HH:mm:ss.SSSZ` format is used.\n\n[source,esql]\n----\nFROM employees\n| KEEP first_name, last_name, hire_date\n| EVAL hired = DATE_FORMAT(hire_date, \"YYYY-MM-dd\")\n----\n", ``` The documents containing `ES|QL` examples, retrieved from ELSER, are sent back to the LLM to answer the original question, per the abridged output below: ``` [llm/start] [1:chain:AgentExecutor > 4:tool:ChainTool > 5:chain:RetrievalQAChain > 7:chain:StuffDocumentsChain > 8:chain:LLMChain > 9:llm:ActionsClientLlm] Entering LLM run with input: { "prompts": [ "Use the following pieces of context to answer the question at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer.\n\n[[esql-date_format]]\n=== `DATE_FORMAT`\nReturns a string representation of a date in the provided format. If no format\nis specified, the `yyyy-MM-dd'T'HH:mm:ss.SSSZ` format is used.\n\n[source,esql]\n----\nFROM employees\n| KEEP first_name, last_name, hire_date\n| EVAL hired = DATE_FORMAT(hire_date, \"YYYY-MM-dd\")\n----\n\n\n[[esql-date_trunc]]\n=== `DATE_TRUNC`\nRounds down a date to the closest interval. Intervals can be expressed using the\n<>.\n\n[source,esql]\n----\nFROM employees\n| EVAL year_hired = DATE_TRUNC(1 year, hire_date)\n| STATS count(emp_no) BY year_hired\n| SORT year_hired\n----\n\n\n[[esql-from]]\n=== `FROM`\n\nThe `FROM` source command returns a table with up to 10,000 documents from a\ndata stream, index, ``` ### Complete (verbose) LangChain output from the example The following `verbose: true` output from LangChain below was produced via the example in the previous section: ``` [chain/start] [1:chain:AgentExecutor] Entering Chain run with input: { "input": "\n\n\n\nFrom employees, I want to see the 5 earliest employees (hire_date), I want to display only the month and the year that they were hired in and their employee number (emp_no). Format the date as e.g. \"September 2019\". Only show the query", "chat_history": [] } [chain/start] [1:chain:AgentExecutor > 2:chain:LLMChain] Entering Chain run with input: { "input": "\n\n\n\nFrom employees, I want to see the 5 earliest employees (hire_date), I want to display only the month and the year that they were hired in and their employee number (emp_no). Format the date as e.g. \"September 2019\". Only show the query", "chat_history": [], "agent_scratchpad": [], "stop": [ "Observation:" ] } [llm/start] [1:chain:AgentExecutor > 2:chain:LLMChain > 3:llm:ActionsClientLlm] Entering LLM run with input: { "prompts": [ "[{\"lc\":1,\"type\":\"constructor\",\"id\":[\"langchain\",\"schema\",\"SystemMessage\"],\"kwargs\":{\"content\":\"Assistant is a large language model trained by OpenAI.\\n\\nAssistant is designed to be able to assist with a wide range of tasks, from answering simple questions to providing in-depth explanations and discussions on a wide range of topics. As a language model, Assistant is able to generate human-like text based on the input it receives, allowing it to engage in natural-sounding conversations and provide responses that are coherent and relevant to the topic at hand.\\n\\nAssistant is constantly learning and improving, and its capabilities are constantly evolving. It is able to process and understand large amounts of text, and can use this knowledge to provide accurate and informative responses to a wide range of questions. Additionally, Assistant is able to generate its own text based on the input it receives, allowing it to engage in discussions and provide explanations and descriptions on a wide range of topics.\\n\\nOverall, Assistant is a powerful system that can help with a wide range of tasks and provide valuable insights and information on a wide range of topics. Whether you need help with a specific question or just want to have a conversation about a particular topic, Assistant is here to assist. However, above all else, all responses must adhere to the format of RESPONSE FORMAT INSTRUCTIONS.\",\"additional_kwargs\":{}}},{\"lc\":1,\"type\":\"constructor\",\"id\":[\"langchain\",\"schema\",\"HumanMessage\"],\"kwargs\":{\"content\":\"TOOLS\\n------\\nAssistant can ask the user to use tools to look up information that may be helpful in answering the users original question. The tools the human can use are:\\n\\nesql-language-knowledge-base: Call this for knowledge on how to build an ESQL query, or answer questions about the ES|QL query language.\\n\\nRESPONSE FORMAT INSTRUCTIONS\\n----------------------------\\n\\nOutput a JSON markdown code snippet containing a valid JSON object in one of two formats:\\n\\n**Option 1:**\\nUse this if you want the human to use a tool.\\nMarkdown code snippet formatted in the following schema:\\n\\n```json\\n{\\n \\\"action\\\": string, // The action to take. Must be one of [esql-language-knowledge-base]\\n \\\"action_input\\\": string // The input to the action. May be a stringified object.\\n}\\n```\\n\\n**Option #2:**\\nUse this if you want to respond directly and conversationally to the human. Markdown code snippet formatted in the following schema:\\n\\n```json\\n{\\n \\\"action\\\": \\\"Final Answer\\\",\\n \\\"action_input\\\": string // You should put what you want to return to use here and make sure to use valid json newline characters.\\n}\\n```\\n\\nFor both options, remember to always include the surrounding markdown code snippet delimiters (begin with \\\"```json\\\" and end with \\\"```\\\")!\\n\\n\\nUSER'S INPUT\\n--------------------\\nHere is the user's input (remember to respond with a markdown code snippet of a json blob with a single action, and NOTHING else):\\n\\n\\n\\n\\n\\nFrom employees, I want to see the 5 earliest employees (hire_date), I want to display only the month and the year that they were hired in and their employee number (emp_no). Format the date as e.g. \\\"September 2019\\\". Only show the query\",\"additional_kwargs\":{}}}]" ] } [llm/end] [1:chain:AgentExecutor > 2:chain:LLMChain > 3:llm:ActionsClientLlm] [3.08s] Exiting LLM run with output: { "generations": [ [ { "text": "```json\n{\n \"action\": \"esql-language-knowledge-base\",\n \"action_input\": \"Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'.\"\n}\n```" } ] ] } [chain/end] [1:chain:AgentExecutor > 2:chain:LLMChain] [3.09s] Exiting Chain run with output: { "text": "```json\n{\n \"action\": \"esql-language-knowledge-base\",\n \"action_input\": \"Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'.\"\n}\n```" } [agent/action] [1:chain:AgentExecutor] Agent selected action: { "tool": "esql-language-knowledge-base", "toolInput": "Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'.", "log": "```json\n{\n \"action\": \"esql-language-knowledge-base\",\n \"action_input\": \"Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'.\"\n}\n```" } [tool/start] [1:chain:AgentExecutor > 4:tool:ChainTool] Entering Tool run with input: "Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'." [chain/start] [1:chain:AgentExecutor > 4:tool:ChainTool > 5:chain:RetrievalQAChain] Entering Chain run with input: { "query": "Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'." } [retriever/start] [1:chain:AgentExecutor > 4:tool:ChainTool > 5:chain:RetrievalQAChain > 6:retriever:VectorStoreRetriever] Entering Retriever run with input: { "query": "Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'." } [retriever/end] [1:chain:AgentExecutor > 4:tool:ChainTool > 5:chain:RetrievalQAChain > 6:retriever:VectorStoreRetriever] [115ms] Exiting Retriever run with output: { "documents": [ { "pageContent": "[[esql-date_format]]\n=== `DATE_FORMAT`\nReturns a string representation of a date in the provided format. If no format\nis specified, the `yyyy-MM-dd'T'HH:mm:ss.SSSZ` format is used.\n\n[source,esql]\n----\nFROM employees\n| KEEP first_name, last_name, hire_date\n| EVAL hired = DATE_FORMAT(hire_date, \"YYYY-MM-dd\")\n----\n", "metadata": { "source": "/Users/andrew.goldstein/Projects/forks/spong/kibana/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/docs/functions/date_format.asciidoc" } }, { "pageContent": "[[esql-date_trunc]]\n=== `DATE_TRUNC`\nRounds down a date to the closest interval. Intervals can be expressed using the\n<>.\n\n[source,esql]\n----\nFROM employees\n| EVAL year_hired = DATE_TRUNC(1 year, hire_date)\n| STATS count(emp_no) BY year_hired\n| SORT year_hired\n----\n", "metadata": { "source": "/Users/andrew.goldstein/Projects/forks/spong/kibana/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/docs/functions/date_trunc.asciidoc" } }, { "pageContent": "[[esql-from]]\n=== `FROM`\n\nThe `FROM` source command returns a table with up to 10,000 documents from a\ndata stream, index, or alias. Each row in the resulting table represents a\ndocument. Each column corresponds to a field, and can be accessed by the name\nof that field.\n\n[source,esql]\n----\nFROM employees\n----\n\nYou can use <> to refer to indices, aliases\nand data streams. This can be useful for time series data, for example to access\ntoday's index:\n\n[source,esql]\n----\nFROM \n----\n\nUse comma-separated lists or wildcards to query multiple data streams, indices,\nor aliases:\n\n[source,esql]\n----\nFROM employees-00001,employees-*\n----\n", "metadata": { "source": "/Users/andrew.goldstein/Projects/forks/spong/kibana/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/docs/source_commands/from.asciidoc" } }, { "pageContent": "[[esql-where]]\n=== `WHERE`\n\nUse `WHERE` to produce a table that contains all the rows from the input table\nfor which the provided condition evaluates to `true`:\n\n[source,esql]\n----\ninclude::{esql-specs}/docs.csv-spec[tag=where]\n----\n\nWhich, if `still_hired` is a boolean field, can be simplified to:\n\n[source,esql]\n----\ninclude::{esql-specs}/docs.csv-spec[tag=whereBoolean]\n----\n\n[discrete]\n==== Operators\n\nRefer to <> for an overview of the supported operators.\n\n[discrete]\n==== Functions\n`WHERE` supports various functions for calculating values. Refer to\n<> for more information.\n\n[source,esql]\n----\ninclude::{esql-specs}/docs.csv-spec[tag=whereFunction]\n----\n", "metadata": { "source": "/Users/andrew.goldstein/Projects/forks/spong/kibana/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/docs/processing_commands/where.asciidoc" } } ] } [chain/start] [1:chain:AgentExecutor > 4:tool:ChainTool > 5:chain:RetrievalQAChain > 7:chain:StuffDocumentsChain] Entering Chain run with input: { "question": "Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'.", "input_documents": [ { "pageContent": "[[esql-date_format]]\n=== `DATE_FORMAT`\nReturns a string representation of a date in the provided format. If no format\nis specified, the `yyyy-MM-dd'T'HH:mm:ss.SSSZ` format is used.\n\n[source,esql]\n----\nFROM employees\n| KEEP first_name, last_name, hire_date\n| EVAL hired = DATE_FORMAT(hire_date, \"YYYY-MM-dd\")\n----\n", "metadata": { "source": "/Users/andrew.goldstein/Projects/forks/spong/kibana/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/docs/functions/date_format.asciidoc" } }, { "pageContent": "[[esql-date_trunc]]\n=== `DATE_TRUNC`\nRounds down a date to the closest interval. Intervals can be expressed using the\n<>.\n\n[source,esql]\n----\nFROM employees\n| EVAL year_hired = DATE_TRUNC(1 year, hire_date)\n| STATS count(emp_no) BY year_hired\n| SORT year_hired\n----\n", "metadata": { "source": "/Users/andrew.goldstein/Projects/forks/spong/kibana/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/docs/functions/date_trunc.asciidoc" } }, { "pageContent": "[[esql-from]]\n=== `FROM`\n\nThe `FROM` source command returns a table with up to 10,000 documents from a\ndata stream, index, or alias. Each row in the resulting table represents a\ndocument. Each column corresponds to a field, and can be accessed by the name\nof that field.\n\n[source,esql]\n----\nFROM employees\n----\n\nYou can use <> to refer to indices, aliases\nand data streams. This can be useful for time series data, for example to access\ntoday's index:\n\n[source,esql]\n----\nFROM \n----\n\nUse comma-separated lists or wildcards to query multiple data streams, indices,\nor aliases:\n\n[source,esql]\n----\nFROM employees-00001,employees-*\n----\n", "metadata": { "source": "/Users/andrew.goldstein/Projects/forks/spong/kibana/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/docs/source_commands/from.asciidoc" } }, { "pageContent": "[[esql-where]]\n=== `WHERE`\n\nUse `WHERE` to produce a table that contains all the rows from the input table\nfor which the provided condition evaluates to `true`:\n\n[source,esql]\n----\ninclude::{esql-specs}/docs.csv-spec[tag=where]\n----\n\nWhich, if `still_hired` is a boolean field, can be simplified to:\n\n[source,esql]\n----\ninclude::{esql-specs}/docs.csv-spec[tag=whereBoolean]\n----\n\n[discrete]\n==== Operators\n\nRefer to <> for an overview of the supported operators.\n\n[discrete]\n==== Functions\n`WHERE` supports various functions for calculating values. Refer to\n<> for more information.\n\n[source,esql]\n----\ninclude::{esql-specs}/docs.csv-spec[tag=whereFunction]\n----\n", "metadata": { "source": "/Users/andrew.goldstein/Projects/forks/spong/kibana/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/docs/processing_commands/where.asciidoc" } } ], "query": "Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'." } [chain/start] [1:chain:AgentExecutor > 4:tool:ChainTool > 5:chain:RetrievalQAChain > 7:chain:StuffDocumentsChain > 8:chain:LLMChain] Entering Chain run with input: { "question": "Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'.", "query": "Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'.", "context": "[[esql-date_format]]\n=== `DATE_FORMAT`\nReturns a string representation of a date in the provided format. If no format\nis specified, the `yyyy-MM-dd'T'HH:mm:ss.SSSZ` format is used.\n\n[source,esql]\n----\nFROM employees\n| KEEP first_name, last_name, hire_date\n| EVAL hired = DATE_FORMAT(hire_date, \"YYYY-MM-dd\")\n----\n\n\n[[esql-date_trunc]]\n=== `DATE_TRUNC`\nRounds down a date to the closest interval. Intervals can be expressed using the\n<>.\n\n[source,esql]\n----\nFROM employees\n| EVAL year_hired = DATE_TRUNC(1 year, hire_date)\n| STATS count(emp_no) BY year_hired\n| SORT year_hired\n----\n\n\n[[esql-from]]\n=== `FROM`\n\nThe `FROM` source command returns a table with up to 10,000 documents from a\ndata stream, index, or alias. Each row in the resulting table represents a\ndocument. Each column corresponds to a field, and can be accessed by the name\nof that field.\n\n[source,esql]\n----\nFROM employees\n----\n\nYou can use <> to refer to indices, aliases\nand data streams. This can be useful for time series data, for example to access\ntoday's index:\n\n[source,esql]\n----\nFROM \n----\n\nUse comma-separated lists or wildcards to query multiple data streams, indices,\nor aliases:\n\n[source,esql]\n----\nFROM employees-00001,employees-*\n----\n\n\n[[esql-where]]\n=== `WHERE`\n\nUse `WHERE` to produce a table that contains all the rows from the input table\nfor which the provided condition evaluates to `true`:\n\n[source,esql]\n----\ninclude::{esql-specs}/docs.csv-spec[tag=where]\n----\n\nWhich, if `still_hired` is a boolean field, can be simplified to:\n\n[source,esql]\n----\ninclude::{esql-specs}/docs.csv-spec[tag=whereBoolean]\n----\n\n[discrete]\n==== Operators\n\nRefer to <> for an overview of the supported operators.\n\n[discrete]\n==== Functions\n`WHERE` supports various functions for calculating values. Refer to\n<> for more information.\n\n[source,esql]\n----\ninclude::{esql-specs}/docs.csv-spec[tag=whereFunction]\n----\n" } [llm/start] [1:chain:AgentExecutor > 4:tool:ChainTool > 5:chain:RetrievalQAChain > 7:chain:StuffDocumentsChain > 8:chain:LLMChain > 9:llm:ActionsClientLlm] Entering LLM run with input: { "prompts": [ "Use the following pieces of context to answer the question at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer.\n\n[[esql-date_format]]\n=== `DATE_FORMAT`\nReturns a string representation of a date in the provided format. If no format\nis specified, the `yyyy-MM-dd'T'HH:mm:ss.SSSZ` format is used.\n\n[source,esql]\n----\nFROM employees\n| KEEP first_name, last_name, hire_date\n| EVAL hired = DATE_FORMAT(hire_date, \"YYYY-MM-dd\")\n----\n\n\n[[esql-date_trunc]]\n=== `DATE_TRUNC`\nRounds down a date to the closest interval. Intervals can be expressed using the\n<>.\n\n[source,esql]\n----\nFROM employees\n| EVAL year_hired = DATE_TRUNC(1 year, hire_date)\n| STATS count(emp_no) BY year_hired\n| SORT year_hired\n----\n\n\n[[esql-from]]\n=== `FROM`\n\nThe `FROM` source command returns a table with up to 10,000 documents from a\ndata stream, index, or alias. Each row in the resulting table represents a\ndocument. Each column corresponds to a field, and can be accessed by the name\nof that field.\n\n[source,esql]\n----\nFROM employees\n----\n\nYou can use <> to refer to indices, aliases\nand data streams. This can be useful for time series data, for example to access\ntoday's index:\n\n[source,esql]\n----\nFROM \n----\n\nUse comma-separated lists or wildcards to query multiple data streams, indices,\nor aliases:\n\n[source,esql]\n----\nFROM employees-00001,employees-*\n----\n\n\n[[esql-where]]\n=== `WHERE`\n\nUse `WHERE` to produce a table that contains all the rows from the input table\nfor which the provided condition evaluates to `true`:\n\n[source,esql]\n----\ninclude::{esql-specs}/docs.csv-spec[tag=where]\n----\n\nWhich, if `still_hired` is a boolean field, can be simplified to:\n\n[source,esql]\n----\ninclude::{esql-specs}/docs.csv-spec[tag=whereBoolean]\n----\n\n[discrete]\n==== Operators\n\nRefer to <> for an overview of the supported operators.\n\n[discrete]\n==== Functions\n`WHERE` supports various functions for calculating values. Refer to\n<> for more information.\n\n[source,esql]\n----\ninclude::{esql-specs}/docs.csv-spec[tag=whereFunction]\n----\n\n\nQuestion: Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'.\nHelpful Answer:" ] } [llm/end] [1:chain:AgentExecutor > 4:tool:ChainTool > 5:chain:RetrievalQAChain > 7:chain:StuffDocumentsChain > 8:chain:LLMChain > 9:llm:ActionsClientLlm] [2.23s] Exiting LLM run with output: { "generations": [ [ { "text": "FROM employees\n| KEEP emp_no, hire_date\n| EVAL month_year = DATE_FORMAT(hire_date, \"MMMM YYYY\")\n| SORT hire_date\n| LIMIT 5" } ] ] } [chain/end] [1:chain:AgentExecutor > 4:tool:ChainTool > 5:chain:RetrievalQAChain > 7:chain:StuffDocumentsChain > 8:chain:LLMChain] [2.23s] Exiting Chain run with output: { "text": "FROM employees\n| KEEP emp_no, hire_date\n| EVAL month_year = DATE_FORMAT(hire_date, \"MMMM YYYY\")\n| SORT hire_date\n| LIMIT 5" } [chain/end] [1:chain:AgentExecutor > 4:tool:ChainTool > 5:chain:RetrievalQAChain > 7:chain:StuffDocumentsChain] [2.23s] Exiting Chain run with output: { "text": "FROM employees\n| KEEP emp_no, hire_date\n| EVAL month_year = DATE_FORMAT(hire_date, \"MMMM YYYY\")\n| SORT hire_date\n| LIMIT 5" } [chain/end] [1:chain:AgentExecutor > 4:tool:ChainTool > 5:chain:RetrievalQAChain] [2.35s] Exiting Chain run with output: { "text": "FROM employees\n| KEEP emp_no, hire_date\n| EVAL month_year = DATE_FORMAT(hire_date, \"MMMM YYYY\")\n| SORT hire_date\n| LIMIT 5" } [tool/end] [1:chain:AgentExecutor > 4:tool:ChainTool] [2.35s] Exiting Tool run with output: "FROM employees | KEEP emp_no, hire_date | EVAL month_year = DATE_FORMAT(hire_date, "MMMM YYYY") | SORT hire_date | LIMIT 5" [chain/start] [1:chain:AgentExecutor > 10:chain:LLMChain] Entering Chain run with input: { "input": "\n\n\n\nFrom employees, I want to see the 5 earliest employees (hire_date), I want to display only the month and the year that they were hired in and their employee number (emp_no). Format the date as e.g. \"September 2019\". Only show the query", "chat_history": [], "agent_scratchpad": [ { "lc": 1, "type": "constructor", "id": [ "langchain", "schema", "AIMessage" ], "kwargs": { "content": "```json\n{\n \"action\": \"esql-language-knowledge-base\",\n \"action_input\": \"Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'.\"\n}\n```", "additional_kwargs": {} } }, { "lc": 1, "type": "constructor", "id": [ "langchain", "schema", "HumanMessage" ], "kwargs": { "content": "TOOL RESPONSE:\n---------------------\nFROM employees\n| KEEP emp_no, hire_date\n| EVAL month_year = DATE_FORMAT(hire_date, \"MMMM YYYY\")\n| SORT hire_date\n| LIMIT 5\n\nUSER'S INPUT\n--------------------\n\nOkay, so what is the response to my last comment? If using information obtained from the tools you must mention it explicitly without mentioning the tool names - I have forgotten all TOOL RESPONSES! Remember to respond with a markdown code snippet of a json blob with a single action, and NOTHING else.", "additional_kwargs": {} } } ], "stop": [ "Observation:" ] } [llm/start] [1:chain:AgentExecutor > 10:chain:LLMChain > 11:llm:ActionsClientLlm] Entering LLM run with input: { "prompts": [ "[{\"lc\":1,\"type\":\"constructor\",\"id\":[\"langchain\",\"schema\",\"SystemMessage\"],\"kwargs\":{\"content\":\"Assistant is a large language model trained by OpenAI.\\n\\nAssistant is designed to be able to assist with a wide range of tasks, from answering simple questions to providing in-depth explanations and discussions on a wide range of topics. As a language model, Assistant is able to generate human-like text based on the input it receives, allowing it to engage in natural-sounding conversations and provide responses that are coherent and relevant to the topic at hand.\\n\\nAssistant is constantly learning and improving, and its capabilities are constantly evolving. It is able to process and understand large amounts of text, and can use this knowledge to provide accurate and informative responses to a wide range of questions. Additionally, Assistant is able to generate its own text based on the input it receives, allowing it to engage in discussions and provide explanations and descriptions on a wide range of topics.\\n\\nOverall, Assistant is a powerful system that can help with a wide range of tasks and provide valuable insights and information on a wide range of topics. Whether you need help with a specific question or just want to have a conversation about a particular topic, Assistant is here to assist. However, above all else, all responses must adhere to the format of RESPONSE FORMAT INSTRUCTIONS.\",\"additional_kwargs\":{}}},{\"lc\":1,\"type\":\"constructor\",\"id\":[\"langchain\",\"schema\",\"HumanMessage\"],\"kwargs\":{\"content\":\"TOOLS\\n------\\nAssistant can ask the user to use tools to look up information that may be helpful in answering the users original question. The tools the human can use are:\\n\\nesql-language-knowledge-base: Call this for knowledge on how to build an ESQL query, or answer questions about the ES|QL query language.\\n\\nRESPONSE FORMAT INSTRUCTIONS\\n----------------------------\\n\\nOutput a JSON markdown code snippet containing a valid JSON object in one of two formats:\\n\\n**Option 1:**\\nUse this if you want the human to use a tool.\\nMarkdown code snippet formatted in the following schema:\\n\\n```json\\n{\\n \\\"action\\\": string, // The action to take. Must be one of [esql-language-knowledge-base]\\n \\\"action_input\\\": string // The input to the action. May be a stringified object.\\n}\\n```\\n\\n**Option #2:**\\nUse this if you want to respond directly and conversationally to the human. Markdown code snippet formatted in the following schema:\\n\\n```json\\n{\\n \\\"action\\\": \\\"Final Answer\\\",\\n \\\"action_input\\\": string // You should put what you want to return to use here and make sure to use valid json newline characters.\\n}\\n```\\n\\nFor both options, remember to always include the surrounding markdown code snippet delimiters (begin with \\\"```json\\\" and end with \\\"```\\\")!\\n\\n\\nUSER'S INPUT\\n--------------------\\nHere is the user's input (remember to respond with a markdown code snippet of a json blob with a single action, and NOTHING else):\\n\\n\\n\\n\\n\\nFrom employees, I want to see the 5 earliest employees (hire_date), I want to display only the month and the year that they were hired in and their employee number (emp_no). Format the date as e.g. \\\"September 2019\\\". Only show the query\",\"additional_kwargs\":{}}},{\"lc\":1,\"type\":\"constructor\",\"id\":[\"langchain\",\"schema\",\"AIMessage\"],\"kwargs\":{\"content\":\"```json\\n{\\n \\\"action\\\": \\\"esql-language-knowledge-base\\\",\\n \\\"action_input\\\": \\\"Display the 'emp_no', month and year of the 5 earliest employees by 'hire_date'. Format the date as 'Month Year'.\\\"\\n}\\n```\",\"additional_kwargs\":{}}},{\"lc\":1,\"type\":\"constructor\",\"id\":[\"langchain\",\"schema\",\"HumanMessage\"],\"kwargs\":{\"content\":\"TOOL RESPONSE:\\n---------------------\\nFROM employees\\n| KEEP emp_no, hire_date\\n| EVAL month_year = DATE_FORMAT(hire_date, \\\"MMMM YYYY\\\")\\n| SORT hire_date\\n| LIMIT 5\\n\\nUSER'S INPUT\\n--------------------\\n\\nOkay, so what is the response to my last comment? If using information obtained from the tools you must mention it explicitly without mentioning the tool names - I have forgotten all TOOL RESPONSES! Remember to respond with a markdown code snippet of a json blob with a single action, and NOTHING else.\",\"additional_kwargs\":{}}}]" ] } [llm/end] [1:chain:AgentExecutor > 10:chain:LLMChain > 11:llm:ActionsClientLlm] [6.47s] Exiting LLM run with output: { "generations": [ [ { "text": "```json\n{\n \"action\": \"Final Answer\",\n \"action_input\": \"Here is the query to get the employee number and the formatted hire date for the 5 earliest employees by hire_date:\\n\\nFROM employees\\n| KEEP emp_no, hire_date\\n| EVAL month_year = DATE_FORMAT(hire_date, \\\"MMMM YYYY\\\")\\n| SORT hire_date\\n| LIMIT 5\"\n}\n```" } ] ] } [chain/end] [1:chain:AgentExecutor > 10:chain:LLMChain] [6.47s] Exiting Chain run with output: { "text": "```json\n{\n \"action\": \"Final Answer\",\n \"action_input\": \"Here is the query to get the employee number and the formatted hire date for the 5 earliest employees by hire_date:\\n\\nFROM employees\\n| KEEP emp_no, hire_date\\n| EVAL month_year = DATE_FORMAT(hire_date, \\\"MMMM YYYY\\\")\\n| SORT hire_date\\n| LIMIT 5\"\n}\n```" } [chain/end] [1:chain:AgentExecutor] [11.91s] Exiting Chain run with output: { "output": "Here is the query to get the employee number and the formatted hire date for the 5 earliest employees by hire_date:\n\nFROM employees\n| KEEP emp_no, hire_date\n| EVAL month_year = DATE_FORMAT(hire_date, \"MMMM YYYY\")\n| SORT hire_date\n| LIMIT 5" } ``` --- .../impl/assistant/api.test.tsx | 84 +++++++++++++++++++ .../impl/assistant/api.tsx | 4 +- .../impl/assistant/helpers.test.ts | 43 +++++++++- .../impl/assistant/helpers.ts | 21 +++++ .../execute_custom_llm_chain/index.test.ts | 29 ++++--- .../execute_custom_llm_chain/index.ts | 39 +++++---- .../post_actions_connector_execute.test.ts | 2 +- .../routes/post_actions_connector_execute.ts | 4 +- 8 files changed, 195 insertions(+), 31 deletions(-) diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.test.tsx index 65b8183b60a0b..2f46e99d12b07 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.test.tsx @@ -126,4 +126,88 @@ describe('fetchConnectorExecuteAction', () => { expect(result).toBe('Test response'); }); + + it('returns the value of the action_input property when assistantLangChain is true, and `content` has properly prefixed and suffixed JSON with the action_input property', async () => { + const content = '```json\n{"action_input": "value from action_input"}\n```'; + + (mockHttp.fetch as jest.Mock).mockResolvedValue({ + status: 'ok', + data: { + choices: [ + { + message: { + content, + }, + }, + ], + }, + }); + + const testProps: FetchConnectorExecuteAction = { + assistantLangChain: true, // <-- requires response parsing + http: mockHttp, + messages, + apiConfig, + }; + + const result = await fetchConnectorExecuteAction(testProps); + + expect(result).toBe('value from action_input'); + }); + + it('returns the original content when assistantLangChain is true, and `content` has properly formatted JSON WITHOUT the action_input property', async () => { + const content = '```json\n{"some_key": "some value"}\n```'; + + (mockHttp.fetch as jest.Mock).mockResolvedValue({ + status: 'ok', + data: { + choices: [ + { + message: { + content, + }, + }, + ], + }, + }); + + const testProps: FetchConnectorExecuteAction = { + assistantLangChain: true, // <-- requires response parsing + http: mockHttp, + messages, + apiConfig, + }; + + const result = await fetchConnectorExecuteAction(testProps); + + expect(result).toBe(content); + }); + + it('returns the original when assistantLangChain is true, and `content` is not JSON', async () => { + const content = 'plain text content'; + + (mockHttp.fetch as jest.Mock).mockResolvedValue({ + status: 'ok', + data: { + choices: [ + { + message: { + content, + }, + }, + ], + }, + }); + + const testProps: FetchConnectorExecuteAction = { + assistantLangChain: true, // <-- requires response parsing + http: mockHttp, + messages, + apiConfig, + }; + + const result = await fetchConnectorExecuteAction(testProps); + + expect(result).toBe(content); + }); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.tsx index 511b5aa585af0..6d3452b6f7880 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.tsx @@ -12,6 +12,7 @@ import { HttpSetup, IHttpFetchError } from '@kbn/core-http-browser'; import type { Conversation, Message } from '../assistant_context/types'; import { API_ERROR } from './translations'; import { MODEL_GPT_3_5_TURBO } from '../connectorland/models/model_selector/model_selector'; +import { getFormattedMessageContent } from './helpers'; export interface FetchConnectorExecuteAction { assistantLangChain: boolean; @@ -78,7 +79,8 @@ export const fetchConnectorExecuteAction = async ({ if (data.choices && data.choices.length > 0 && data.choices[0].message.content) { const result = data.choices[0].message.content.trim(); - return result; + + return assistantLangChain ? getFormattedMessageContent(result) : result; } else { return API_ERROR; } diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.test.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.test.ts index 69bed887e730e..f2b89a07c319e 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.test.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.test.ts @@ -5,7 +5,11 @@ * 2.0. */ -import { getDefaultConnector, getBlockBotConversation } from './helpers'; +import { + getBlockBotConversation, + getDefaultConnector, + getFormattedMessageContent, +} from './helpers'; import { enterpriseMessaging } from './use_conversation/sample_conversations'; import { ActionConnector } from '@kbn/triggers-actions-ui-plugin/public'; @@ -190,4 +194,41 @@ describe('getBlockBotConversation', () => { expect(result).toBeUndefined(); }); }); + + describe('getFormattedMessageContent', () => { + it('returns the value of the action_input property when `content` has properly prefixed and suffixed JSON with the action_input property', () => { + const content = '```json\n{"action_input": "value from action_input"}\n```'; + + expect(getFormattedMessageContent(content)).toBe('value from action_input'); + }); + + it('returns the original content when `content` has properly formatted JSON WITHOUT the action_input property', () => { + const content = '```json\n{"some_key": "some value"}\n```'; + expect(getFormattedMessageContent(content)).toBe(content); + }); + + it('returns the original content when `content` has improperly formatted JSON', () => { + const content = '```json\n{"action_input": "value from action_input",}\n```'; // <-- the trailing comma makes it invalid + + expect(getFormattedMessageContent(content)).toBe(content); + }); + + it('returns the original content when `content` is missing the prefix', () => { + const content = '{"action_input": "value from action_input"}\n```'; // <-- missing prefix + + expect(getFormattedMessageContent(content)).toBe(content); + }); + + it('returns the original content when `content` is missing the suffix', () => { + const content = '```json\n{"action_input": "value from action_input"}'; // <-- missing suffix + + expect(getFormattedMessageContent(content)).toBe(content); + }); + + it('returns the original content when `content` does NOT contain a JSON string', () => { + const content = 'plain text content'; + + expect(getFormattedMessageContent(content)).toBe(content); + }); + }); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.ts index b01c9001e8319..2b2c5b76851f7 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.ts @@ -59,3 +59,24 @@ export const getDefaultConnector = ( connectors: Array, Record>> | undefined ): ActionConnector, Record> | undefined => connectors?.length === 1 ? connectors[0] : undefined; + +/** + * When `content` is a JSON string, prefixed with "```json\n" + * and suffixed with "\n```", this function will attempt to parse it and return + * the `action_input` property if it exists. + */ +export const getFormattedMessageContent = (content: string): string => { + const formattedContentMatch = content.match(/```json\n([\s\S]+)\n```/); + + if (formattedContentMatch) { + try { + const parsedContent = JSON.parse(formattedContentMatch[1]); + + return parsedContent.action_input ?? content; + } catch { + // we don't want to throw an error here, so we'll fall back to the original content + } + } + + return content; +}; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.test.ts index be1adbc2e1ce4..67fb3859b9943 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.test.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.test.ts @@ -12,7 +12,7 @@ import { ResponseBody } from '../helpers'; import { ActionsClientLlm } from '../llm/actions_client_llm'; import { mockActionResultData } from '../../../__mocks__/action_result_data'; import { langChainMessages } from '../../../__mocks__/lang_chain_messages'; -import { executeCustomLlmChain } from '.'; +import { callAgentExecutor } from '.'; import { loggerMock } from '@kbn/logging-mocks'; import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; @@ -23,11 +23,18 @@ const mockConversationChain = { }; jest.mock('langchain/chains', () => ({ - ConversationalRetrievalQAChain: { + RetrievalQAChain: { fromLLM: jest.fn().mockImplementation(() => mockConversationChain), }, })); +const mockCall = jest.fn(); +jest.mock('langchain/agents', () => ({ + initializeAgentExecutorWithOptions: jest.fn().mockImplementation(() => ({ + call: mockCall, + })), +})); + const mockConnectorId = 'mock-connector-id'; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -42,7 +49,7 @@ const mockActions: ActionsPluginStart = {} as ActionsPluginStart; const mockLogger = loggerMock.create(); const esClientMock = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; -describe('executeCustomLlmChain', () => { +describe('callAgentExecutor', () => { beforeEach(() => { jest.clearAllMocks(); @@ -52,7 +59,7 @@ describe('executeCustomLlmChain', () => { }); it('creates an instance of ActionsClientLlm with the expected context from the request', async () => { - await executeCustomLlmChain({ + await callAgentExecutor({ actions: mockActions, connectorId: mockConnectorId, esClient: esClientMock, @@ -70,7 +77,7 @@ describe('executeCustomLlmChain', () => { }); it('kicks off the chain with (only) the last message', async () => { - await executeCustomLlmChain({ + await callAgentExecutor({ actions: mockActions, connectorId: mockConnectorId, esClient: esClientMock, @@ -79,15 +86,15 @@ describe('executeCustomLlmChain', () => { request: mockRequest, }); - expect(mockConversationChain.call).toHaveBeenCalledWith({ - question: '\n\nDo you know my name?', + expect(mockCall).toHaveBeenCalledWith({ + input: '\n\nDo you know my name?', }); }); it('kicks off the chain with the expected message when langChainMessages has only one entry', async () => { const onlyOneMessage = [langChainMessages[0]]; - await executeCustomLlmChain({ + await callAgentExecutor({ actions: mockActions, connectorId: mockConnectorId, esClient: esClientMock, @@ -96,13 +103,13 @@ describe('executeCustomLlmChain', () => { request: mockRequest, }); - expect(mockConversationChain.call).toHaveBeenCalledWith({ - question: 'What is my name?', + expect(mockCall).toHaveBeenCalledWith({ + input: 'What is my name?', }); }); it('returns the expected response body', async () => { - const result: ResponseBody = await executeCustomLlmChain({ + const result: ResponseBody = await callAgentExecutor({ actions: mockActions, connectorId: mockConnectorId, esClient: esClientMock, diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts index 5a65b1589b21e..b6a768ad69598 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts @@ -7,16 +7,18 @@ import { ElasticsearchClient, KibanaRequest, Logger } from '@kbn/core/server'; import type { PluginStartContract as ActionsPluginStart } from '@kbn/actions-plugin/server'; +import { initializeAgentExecutorWithOptions } from 'langchain/agents'; +import { RetrievalQAChain } from 'langchain/chains'; import { BufferMemory, ChatMessageHistory } from 'langchain/memory'; import { BaseMessage } from 'langchain/schema'; +import { ChainTool, Tool } from 'langchain/tools'; -import { ConversationalRetrievalQAChain } from 'langchain/chains'; +import { ElasticsearchStore } from '../elasticsearch_store/elasticsearch_store'; import { ResponseBody } from '../helpers'; import { ActionsClientLlm } from '../llm/actions_client_llm'; -import { ElasticsearchStore } from '../elasticsearch_store/elasticsearch_store'; import { KNOWLEDGE_BASE_INDEX_PATTERN } from '../../../routes/knowledge_base/constants'; -export const executeCustomLlmChain = async ({ +export const callAgentExecutor = async ({ actions, connectorId, esClient, @@ -34,31 +36,38 @@ export const executeCustomLlmChain = async ({ }): Promise => { const llm = new ActionsClientLlm({ actions, connectorId, request, logger }); - // Chat History Memory: in-memory memory, from client local storage, first message is the system prompt const pastMessages = langChainMessages.slice(0, -1); // all but the last message const latestMessage = langChainMessages.slice(-1); // the last message + const memory = new BufferMemory({ chatHistory: new ChatMessageHistory(pastMessages), - memoryKey: 'chat_history', + memoryKey: 'chat_history', // this is the key expected by https://github.com/langchain-ai/langchainjs/blob/a13a8969345b0f149c1ca4a120d63508b06c52a5/langchain/src/agents/initialize.ts#L166 + inputKey: 'input', + outputKey: 'output', + returnMessages: true, }); // ELSER backed ElasticsearchStore for Knowledge Base const esStore = new ElasticsearchStore(esClient, KNOWLEDGE_BASE_INDEX_PATTERN, logger); + const chain = RetrievalQAChain.fromLLM(llm, esStore.asRetriever()); + + const tools: Tool[] = [ + new ChainTool({ + name: 'esql-language-knowledge-base', + description: + 'Call this for knowledge on how to build an ESQL query, or answer questions about the ES|QL query language.', + chain, + }), + ]; - // Chain w/ chat history memory and knowledge base retriever - const chain = ConversationalRetrievalQAChain.fromLLM(llm, esStore.asRetriever(), { + const executor = await initializeAgentExecutorWithOptions(tools, llm, { + agentType: 'chat-conversational-react-description', memory, - // See `qaChainOptions` from https://js.langchain.com/docs/modules/chains/popular/chat_vector_db - qaChainOptions: { type: 'stuff' }, + verbose: false, }); - await chain.call({ question: latestMessage[0].content }); - // Chain w/ just knowledge base retriever - // const chain = RetrievalQAChain.fromLLM(llm, esStore.asRetriever()); - // await chain.call({ query: latestMessage[0].content }); + await executor.call({ input: latestMessage[0].content }); - // The assistant (on the client side) expects the same response returned - // from the actions framework, so we need to return the same shape of data: return { connector_id: connectorId, data: llm.getActionResultData(), // the response from the actions framework diff --git a/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.test.ts b/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.test.ts index 2e6709a6e33c2..57f2b25f5a65f 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.test.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.test.ts @@ -20,7 +20,7 @@ jest.mock('../lib/build_response', () => ({ })); jest.mock('../lib/langchain/execute_custom_llm_chain', () => ({ - executeCustomLlmChain: jest.fn().mockImplementation( + callAgentExecutor: jest.fn().mockImplementation( async ({ connectorId, }: { diff --git a/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts b/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts index 1043f68f0f9c1..bbb1c76e3e579 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts @@ -20,7 +20,7 @@ import { PostActionsConnectorExecutePathParams, } from '../schemas/post_actions_connector_execute'; import { ElasticAssistantRequestHandlerContext } from '../types'; -import { executeCustomLlmChain } from '../lib/langchain/execute_custom_llm_chain'; +import { callAgentExecutor } from '../lib/langchain/execute_custom_llm_chain'; export const postActionsConnectorExecuteRoute = ( router: IRouter @@ -53,7 +53,7 @@ export const postActionsConnectorExecuteRoute = ( // convert the assistant messages to LangChain messages: const langChainMessages = getLangChainMessages(assistantMessages); - const langChainResponseBody = await executeCustomLlmChain({ + const langChainResponseBody = await callAgentExecutor({ actions, connectorId, esClient, From d941c4a5658769f823fa08fb801303bde8292ff9 Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Mon, 25 Sep 2023 13:58:12 -0400 Subject: [PATCH 28/45] unskip serverless dashboard import tests (#167161) Unskips the serverless Dashboard import test. --- .../test_suites/search/dashboards/import_dashboard.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/test_serverless/functional/test_suites/search/dashboards/import_dashboard.ts b/x-pack/test_serverless/functional/test_suites/search/dashboards/import_dashboard.ts index c935ab3f15f83..30d99d112e640 100644 --- a/x-pack/test_serverless/functional/test_suites/search/dashboards/import_dashboard.ts +++ b/x-pack/test_serverless/functional/test_suites/search/dashboards/import_dashboard.ts @@ -27,8 +27,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'svlCommonPage', ]); - // Failing: See https://github.com/elastic/kibana/issues/166573 - describe.skip('Importing an existing dashboard', () => { + describe('Importing an existing dashboard', () => { before(async () => { await PageObjects.svlCommonPage.login(); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); From f23f2f49dbba97350d7159c6d96d0fbb1ef25d84 Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Mon, 25 Sep 2023 14:04:31 -0400 Subject: [PATCH 29/45] [Canvas] Remove Kui style sheet import (#167054) removes import of the kui_light stylesheet from Canvas shareable runtime. --- x-pack/plugins/canvas/shareable_runtime/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/canvas/shareable_runtime/index.ts b/x-pack/plugins/canvas/shareable_runtime/index.ts index aee57c3780503..475989494c574 100644 --- a/x-pack/plugins/canvas/shareable_runtime/index.ts +++ b/x-pack/plugins/canvas/shareable_runtime/index.ts @@ -9,4 +9,3 @@ export * from './api'; import '@kbn/core-apps-server-internal/assets/legacy_light_theme.css'; import '../public/style/index.scss'; import '@elastic/eui/dist/eui_theme_light.css'; -import '@kbn/ui-framework/dist/kui_light.css'; From c20d177a036be73d7b1180dc17e644afa260994f Mon Sep 17 00:00:00 2001 From: Kyle Pollich Date: Mon, 25 Sep 2023 14:05:03 -0400 Subject: [PATCH 30/45] [Fleet] Increase package install max timeout + add concurrency control to rollovers (#166775) Fixes https://github.com/elastic/kibana/issues/166761 Ref https://github.com/elastic/kibana/issues/162772 ## Summary - Increase overall timeout for waiting to retry "stuck" installations from 1 minute to 30 minutes - Add `pMap` concurrency control limiting concurrent `putMapping` + `rollover` requests to mitigate ES load --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/fleet/common/constants/epm.ts | 2 +- .../epm/elasticsearch/template/template.ts | 25 ++- .../epm/packages/_install_package.test.ts | 144 +++++++++++++++++- .../services/epm/packages/_install_package.ts | 32 ++-- 4 files changed, 179 insertions(+), 24 deletions(-) diff --git a/x-pack/plugins/fleet/common/constants/epm.ts b/x-pack/plugins/fleet/common/constants/epm.ts index 52cb24271afa5..3548fee93fbf2 100644 --- a/x-pack/plugins/fleet/common/constants/epm.ts +++ b/x-pack/plugins/fleet/common/constants/epm.ts @@ -9,7 +9,7 @@ import { ElasticsearchAssetType, KibanaAssetType } from '../types/models'; export const PACKAGES_SAVED_OBJECT_TYPE = 'epm-packages'; export const ASSETS_SAVED_OBJECT_TYPE = 'epm-packages-assets'; -export const MAX_TIME_COMPLETE_INSTALL = 60000; +export const MAX_TIME_COMPLETE_INSTALL = 30 * 60 * 1000; // 30 minutes export const FLEET_SYSTEM_PACKAGE = 'system'; export const FLEET_ELASTIC_AGENT_PACKAGE = 'elastic_agent'; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts index 3e9363fa9828f..5682749d7e381 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts @@ -11,6 +11,8 @@ import type { MappingTypeMapping, } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import pMap from 'p-map'; + import type { Field, Fields } from '../../fields/field'; import type { RegistryDataStream, @@ -729,15 +731,22 @@ const updateAllDataStreams = async ( esClient: ElasticsearchClient, logger: Logger ): Promise => { - const updatedataStreamPromises = indexNameWithTemplates.map((templateEntry) => { - return updateExistingDataStream({ - esClient, - logger, - dataStreamName: templateEntry.dataStreamName, - }); - }); - await Promise.all(updatedataStreamPromises); + await pMap( + indexNameWithTemplates, + (templateEntry) => { + return updateExistingDataStream({ + esClient, + logger, + dataStreamName: templateEntry.dataStreamName, + }); + }, + { + // Limit concurrent putMapping/rollover requests to avoid overhwhelming ES cluster + concurrency: 20, + } + ); }; + const updateExistingDataStream = async ({ dataStreamName, esClient, diff --git a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.test.ts index 3c308b8e85b0a..b7fe0d95310ef 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.test.ts @@ -5,11 +5,21 @@ * 2.0. */ -import type { SavedObjectsClientContract, ElasticsearchClient } from '@kbn/core/server'; +import type { + SavedObjectsClientContract, + ElasticsearchClient, + SavedObject, +} from '@kbn/core/server'; import { savedObjectsClientMock, elasticsearchServiceMock } from '@kbn/core/server/mocks'; import { loggerMock } from '@kbn/logging-mocks'; import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common/constants'; +import { ConcurrentInstallOperationError } from '../../../errors'; + +import type { Installation } from '../../../../common'; + +import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../../common'; + import { appContextService } from '../../app_context'; import { createAppContextStartContractMock } from '../../../mocks'; import { saveArchiveEntries } from '../archive/storage'; @@ -29,7 +39,9 @@ jest.mock('../elasticsearch/datastream_ilm/install'); import { updateCurrentWriteIndices } from '../elasticsearch/template/template'; import { installKibanaAssetsAndReferences } from '../kibana/assets/install'; -import { installIndexTemplatesAndPipelines } from './install'; +import { MAX_TIME_COMPLETE_INSTALL } from '../../../../common/constants'; + +import { installIndexTemplatesAndPipelines, restartInstallation } from './install'; import { _installPackage } from './_install_package'; @@ -69,9 +81,7 @@ describe('_installPackage', () => { jest.mocked(saveArchiveEntries).mockResolvedValue({ saved_objects: [], }); - }); - afterEach(async () => { - appContextService.stop(); + jest.mocked(restartInstallation).mockReset(); }); it('handles errors from installKibanaAssets', async () => { // force errors from this function @@ -226,4 +236,128 @@ describe('_installPackage', () => { expect(installILMPolicy).toBeCalled(); expect(installIlmForDataStream).toBeCalled(); }); + + describe('when package is stuck in `installing`', () => { + afterEach(() => {}); + const mockInstalledPackageSo: SavedObject = { + id: 'mocked-package', + attributes: { + name: 'test-package', + version: '1.0.0', + install_status: 'installing', + install_version: '1.0.0', + install_started_at: new Date().toISOString(), + install_source: 'registry', + verification_status: 'verified', + installed_kibana: [] as any, + installed_es: [] as any, + es_index_patterns: {}, + }, + type: PACKAGES_SAVED_OBJECT_TYPE, + references: [], + }; + + beforeEach(() => { + appContextService.start( + createAppContextStartContractMock({ + internal: { + disableILMPolicies: true, + disableProxies: false, + fleetServerStandalone: false, + onlyAllowAgentUpgradeToKnownVersions: false, + registry: { + kibanaVersionCheckEnabled: true, + capabilities: [], + }, + }, + }) + ); + }); + + describe('timeout reached', () => { + it('restarts installation', async () => { + await _installPackage({ + savedObjectsClient: soClient, + // @ts-ignore + savedObjectsImporter: jest.fn(), + esClient, + logger: loggerMock.create(), + paths: [], + packageInfo: { + name: mockInstalledPackageSo.attributes.name, + version: mockInstalledPackageSo.attributes.version, + title: mockInstalledPackageSo.attributes.name, + } as any, + installedPkg: { + ...mockInstalledPackageSo, + attributes: { + ...mockInstalledPackageSo.attributes, + install_started_at: new Date( + Date.now() - MAX_TIME_COMPLETE_INSTALL * 2 + ).toISOString(), + }, + }, + }); + + expect(restartInstallation).toBeCalled(); + }); + }); + + describe('timeout not reached', () => { + describe('force flag not provided', () => { + it('throws concurrent installation error if force flag is not provided', async () => { + expect( + _installPackage({ + savedObjectsClient: soClient, + // @ts-ignore + savedObjectsImporter: jest.fn(), + esClient, + logger: loggerMock.create(), + paths: [], + packageInfo: { + name: mockInstalledPackageSo.attributes.name, + version: mockInstalledPackageSo.attributes.version, + title: mockInstalledPackageSo.attributes.name, + } as any, + installedPkg: { + ...mockInstalledPackageSo, + attributes: { + ...mockInstalledPackageSo.attributes, + install_started_at: new Date(Date.now() - 1000).toISOString(), + }, + }, + }) + ).rejects.toThrowError(ConcurrentInstallOperationError); + }); + }); + + describe('force flag provided', () => { + it('restarts installation', async () => { + await _installPackage({ + savedObjectsClient: soClient, + // @ts-ignore + savedObjectsImporter: jest.fn(), + esClient, + logger: loggerMock.create(), + paths: [], + packageInfo: { + name: mockInstalledPackageSo.attributes.name, + version: mockInstalledPackageSo.attributes.version, + title: mockInstalledPackageSo.attributes.name, + } as any, + installedPkg: { + ...mockInstalledPackageSo, + attributes: { + ...mockInstalledPackageSo.attributes, + install_started_at: new Date(Date.now() - 1000).toISOString(), + }, + }, + force: true, + }); + + expect(restartInstallation).toBeCalled(); + }); + }); + }); + }); }); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts index 337cf59bbd613..3bfc74bf68968 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts @@ -99,18 +99,30 @@ export async function _installPackage({ try { // if some installation already exists if (installedPkg) { + const isStatusInstalling = installedPkg.attributes.install_status === 'installing'; + const hasExceededTimeout = + Date.now() - Date.parse(installedPkg.attributes.install_started_at) < + MAX_TIME_COMPLETE_INSTALL; + // if the installation is currently running, don't try to install // instead, only return already installed assets - if ( - installedPkg.attributes.install_status === 'installing' && - Date.now() - Date.parse(installedPkg.attributes.install_started_at) < - MAX_TIME_COMPLETE_INSTALL - ) { - throw new ConcurrentInstallOperationError( - `Concurrent installation or upgrade of ${pkgName || 'unknown'}-${ - pkgVersion || 'unknown' - } detected, aborting.` - ); + if (isStatusInstalling && hasExceededTimeout) { + // If this is a forced installation, ignore the timeout and restart the installation anyway + if (force) { + await restartInstallation({ + savedObjectsClient, + pkgName, + pkgVersion, + installSource, + verificationResult, + }); + } else { + throw new ConcurrentInstallOperationError( + `Concurrent installation or upgrade of ${pkgName || 'unknown'}-${ + pkgVersion || 'unknown' + } detected, aborting.` + ); + } } else { // if no installation is running, or the installation has been running longer than MAX_TIME_COMPLETE_INSTALL // (it might be stuck) update the saved object and proceed From da2695fef32513e43e9ef20e3faf4fdcf6ca463b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopyci=C5=84ski?= Date: Mon, 25 Sep 2023 18:34:47 +0000 Subject: [PATCH 31/45] [security_solution] Skip search_filter.cy.ts (#167177) ## Summary image --- .../e2e/investigations/timelines/discover/search_filter.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/discover/search_filter.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/discover/search_filter.cy.ts index afedab5dbb094..c48fa80baad46 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/discover/search_filter.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/discover/search_filter.cy.ts @@ -38,7 +38,8 @@ const INITIAL_START_DATE = 'Jan 18, 2021 @ 20:33:29.186'; const INITIAL_END_DATE = 'Jan 19, 2024 @ 20:33:29.186'; const NEW_START_DATE = 'Jan 18, 2023 @ 20:33:29.186'; -describe( +// Failing: See https://github.com/elastic/kibana/issues/167186 +describe.skip( 'Basic discover search and filter operations', { env: { ftrConfig: { enableExperimental: ['discoverInTimeline'] } }, From f73f70ccdd7c7295a0462ec85be0e9ec6690b98a Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Mon, 25 Sep 2023 15:01:56 -0400 Subject: [PATCH 32/45] [Fleet] Improve config output validation for default output (#167085) --- x-pack/plugins/fleet/server/config.test.ts | 73 ++++++ x-pack/plugins/fleet/server/config.ts | 269 +++++++++++---------- 2 files changed, 215 insertions(+), 127 deletions(-) create mode 100644 x-pack/plugins/fleet/server/config.test.ts diff --git a/x-pack/plugins/fleet/server/config.test.ts b/x-pack/plugins/fleet/server/config.test.ts new file mode 100644 index 0000000000000..da654244aae30 --- /dev/null +++ b/x-pack/plugins/fleet/server/config.test.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 { config } from './config'; + +describe('Config schema', () => { + it('should not allow to specify both default output in xpack.fleet.ouputs and xpack.fleet.agents.elasticsearch.hosts ', () => { + expect(() => { + config.schema.validate({ + agents: { elasticsearch: { hosts: ['https://elasticsearch:9200'] } }, + outputs: [ + { + id: 'test', + name: 'test output', + type: 'elasticsearch', + hosts: ['http://elasticsearch:9200'], + is_default: true, + is_default_monitoring: true, + }, + ], + }); + }).toThrowErrorMatchingInlineSnapshot( + `"xpack.fleet.agents.elasticsearch.hosts should not be used when defining default outputs in xpack.fleet.outputs, please remove it."` + ); + }); + + it('should allow to specify both outputs in xpack.fleet.ouputs without default outputs and xpack.fleet.agents.elasticsearch.hosts ', () => { + expect(() => { + config.schema.validate({ + agents: { elasticsearch: { hosts: ['https://elasticsearch:9200'] } }, + outputs: [ + { + id: 'test', + name: 'test output', + type: 'elasticsearch', + hosts: ['http://elasticsearch:9200'], + is_default: false, + is_default_monitoring: false, + }, + ], + }); + }).not.toThrow(); + }); + + it('should allow to specify default outputs only xpack.fleet.ouputs ', () => { + expect(() => { + config.schema.validate({ + outputs: [ + { + id: 'test', + name: 'test output', + type: 'elasticsearch', + hosts: ['http://elasticsearch:9200'], + is_default: true, + is_default_monitoring: true, + }, + ], + }); + }).not.toThrow(); + }); + + it('should allow to specify default output only in xpack.fleet.agents.elasticsearch.hosts ', () => { + expect(() => { + config.schema.validate({ + agents: { elasticsearch: { hosts: ['https://elasticsearch:9200'] } }, + }); + }).not.toThrow(); + }); +}); diff --git a/x-pack/plugins/fleet/server/config.ts b/x-pack/plugins/fleet/server/config.ts index 49e80690a261c..cbf38a2024733 100644 --- a/x-pack/plugins/fleet/server/config.ts +++ b/x-pack/plugins/fleet/server/config.ts @@ -111,142 +111,157 @@ export const config: PluginConfigDescriptor = { return fullConfig; }, ], - schema: schema.object({ - registryUrl: schema.maybe(schema.uri({ scheme: ['http', 'https'] })), - registryProxyUrl: schema.maybe(schema.uri({ scheme: ['http', 'https'] })), - agents: schema.object({ - enabled: schema.boolean({ defaultValue: true }), - elasticsearch: schema.object({ - hosts: schema.maybe(schema.arrayOf(schema.uri({ scheme: ['http', 'https'] }))), - ca_sha256: schema.maybe(schema.string()), + schema: schema.object( + { + registryUrl: schema.maybe(schema.uri({ scheme: ['http', 'https'] })), + registryProxyUrl: schema.maybe(schema.uri({ scheme: ['http', 'https'] })), + agents: schema.object({ + enabled: schema.boolean({ defaultValue: true }), + elasticsearch: schema.object({ + hosts: schema.maybe(schema.arrayOf(schema.uri({ scheme: ['http', 'https'] }))), + ca_sha256: schema.maybe(schema.string()), + }), + fleet_server: schema.maybe( + schema.object({ + hosts: schema.maybe(schema.arrayOf(schema.uri({ scheme: ['http', 'https'] }))), + }) + ), }), - fleet_server: schema.maybe( + packages: PreconfiguredPackagesSchema, + agentPolicies: PreconfiguredAgentPoliciesSchema, + outputs: PreconfiguredOutputsSchema, + fleetServerHosts: PreconfiguredFleetServerHostsSchema, + proxies: PreconfiguredFleetProxiesSchema, + agentIdVerificationEnabled: schema.boolean({ defaultValue: true }), + setup: schema.maybe( schema.object({ - hosts: schema.maybe(schema.arrayOf(schema.uri({ scheme: ['http', 'https'] }))), + agentPolicySchemaUpgradeBatchSize: schema.maybe(schema.number()), }) ), - }), - packages: PreconfiguredPackagesSchema, - agentPolicies: PreconfiguredAgentPoliciesSchema, - outputs: PreconfiguredOutputsSchema, - fleetServerHosts: PreconfiguredFleetServerHostsSchema, - proxies: PreconfiguredFleetProxiesSchema, - agentIdVerificationEnabled: schema.boolean({ defaultValue: true }), - setup: schema.maybe( - schema.object({ - agentPolicySchemaUpgradeBatchSize: schema.maybe(schema.number()), - }) - ), - developer: schema.object({ - maxAgentPoliciesWithInactivityTimeout: schema.maybe(schema.number()), - disableRegistryVersionCheck: schema.boolean({ defaultValue: false }), - allowAgentUpgradeSourceUri: schema.boolean({ defaultValue: false }), - bundledPackageLocation: schema.string({ defaultValue: DEFAULT_BUNDLED_PACKAGE_LOCATION }), - }), - packageVerification: schema.object({ - gpgKeyPath: schema.string({ defaultValue: DEFAULT_GPG_KEY_PATH }), - }), - /** - * For internal use. A list of string values (comma delimited) that will enable experimental - * type of functionality that is not yet released. - * - * @example - * xpack.fleet.enableExperimental: - * - feature1 - * - feature2 - */ - enableExperimental: schema.arrayOf(schema.string(), { - defaultValue: () => [], - validate(list) { - for (const key of list) { - if (!isValidExperimentalValue(key)) { - return `[${key}] is not allowed. Allowed values are: ${allowedExperimentalValues.join( - ', ' - )}`; + developer: schema.object({ + maxAgentPoliciesWithInactivityTimeout: schema.maybe(schema.number()), + disableRegistryVersionCheck: schema.boolean({ defaultValue: false }), + allowAgentUpgradeSourceUri: schema.boolean({ defaultValue: false }), + bundledPackageLocation: schema.string({ defaultValue: DEFAULT_BUNDLED_PACKAGE_LOCATION }), + }), + packageVerification: schema.object({ + gpgKeyPath: schema.string({ defaultValue: DEFAULT_GPG_KEY_PATH }), + }), + /** + * For internal use. A list of string values (comma delimited) that will enable experimental + * type of functionality that is not yet released. + * + * @example + * xpack.fleet.enableExperimental: + * - feature1 + * - feature2 + */ + enableExperimental: schema.arrayOf(schema.string(), { + defaultValue: () => [], + validate(list) { + for (const key of list) { + if (!isValidExperimentalValue(key)) { + return `[${key}] is not allowed. Allowed values are: ${allowedExperimentalValues.join( + ', ' + )}`; + } } - } - }, - }), + }, + }), - internal: schema.maybe( - schema.object({ - disableILMPolicies: schema.boolean({ - defaultValue: false, - }), - disableProxies: schema.boolean({ - defaultValue: false, - }), - fleetServerStandalone: schema.boolean({ - defaultValue: false, - }), - onlyAllowAgentUpgradeToKnownVersions: schema.boolean({ - defaultValue: false, - }), - activeAgentsSoftLimit: schema.maybe( - schema.number({ - min: 0, - }) - ), - registry: schema.object( - { - kibanaVersionCheckEnabled: schema.boolean({ defaultValue: true }), - spec: schema.object( - { - min: schema.maybe(schema.string()), - max: schema.string({ defaultValue: REGISTRY_SPEC_MAX_VERSION }), - }, - { - defaultValue: { + internal: schema.maybe( + schema.object({ + disableILMPolicies: schema.boolean({ + defaultValue: false, + }), + disableProxies: schema.boolean({ + defaultValue: false, + }), + fleetServerStandalone: schema.boolean({ + defaultValue: false, + }), + onlyAllowAgentUpgradeToKnownVersions: schema.boolean({ + defaultValue: false, + }), + activeAgentsSoftLimit: schema.maybe( + schema.number({ + min: 0, + }) + ), + registry: schema.object( + { + kibanaVersionCheckEnabled: schema.boolean({ defaultValue: true }), + spec: schema.object( + { + min: schema.maybe(schema.string()), + max: schema.string({ defaultValue: REGISTRY_SPEC_MAX_VERSION }), + }, + { + defaultValue: { + max: REGISTRY_SPEC_MAX_VERSION, + }, + } + ), + capabilities: schema.arrayOf( + schema.oneOf([ + // See package-spec for the list of available capiblities https://github.com/elastic/package-spec/blob/dcc37b652690f8a2bca9cf8a12fc28fd015730a0/spec/integration/manifest.spec.yml#L113 + schema.literal('apm'), + schema.literal('enterprise_search'), + schema.literal('observability'), + schema.literal('security'), + schema.literal('serverless_search'), + schema.literal('uptime'), + ]), + { defaultValue: [] } + ), + }, + { + defaultValue: { + kibanaVersionCheckEnabled: true, + capabilities: [], + spec: { max: REGISTRY_SPEC_MAX_VERSION, }, - } - ), - capabilities: schema.arrayOf( - schema.oneOf([ - // See package-spec for the list of available capiblities https://github.com/elastic/package-spec/blob/dcc37b652690f8a2bca9cf8a12fc28fd015730a0/spec/integration/manifest.spec.yml#L113 - schema.literal('apm'), - schema.literal('enterprise_search'), - schema.literal('observability'), - schema.literal('security'), - schema.literal('serverless_search'), - schema.literal('uptime'), - ]), - { defaultValue: [] } - ), - }, - { - defaultValue: { - kibanaVersionCheckEnabled: true, - capabilities: [], - spec: { - max: REGISTRY_SPEC_MAX_VERSION, }, - }, - } - ), - }) - ), - enabled: schema.boolean({ defaultValue: true }), - /** - * The max size of the artifacts encoded_size sum in a batch when more than one (there is at least one artifact in a batch). - * @example - * artifact1.encoded_size = 400 - * artifact2.encoded_size = 600 - * artifact3.encoded_size = 1_200 - * and - * createArtifactsBulkBatchSize: 1_000 - * then - * batch1 = [artifact1, artifact2] - * batch2 = [artifact3] - */ - createArtifactsBulkBatchSize: schema.maybe( - schema.number({ - defaultValue: BULK_CREATE_MAX_ARTIFACTS_BYTES, - max: 4_000_000, - min: 400, - }) - ), - }), + } + ), + }) + ), + enabled: schema.boolean({ defaultValue: true }), + /** + * The max size of the artifacts encoded_size sum in a batch when more than one (there is at least one artifact in a batch). + * @example + * artifact1.encoded_size = 400 + * artifact2.encoded_size = 600 + * artifact3.encoded_size = 1_200 + * and + * createArtifactsBulkBatchSize: 1_000 + * then + * batch1 = [artifact1, artifact2] + * batch2 = [artifact3] + */ + createArtifactsBulkBatchSize: schema.maybe( + schema.number({ + defaultValue: BULK_CREATE_MAX_ARTIFACTS_BYTES, + max: 4_000_000, + min: 400, + }) + ), + }, + { + validate: (configToValidate) => { + const hasDefaultPreconfiguredOuputs = configToValidate.outputs.some( + (o) => o.is_default || o.is_default_monitoring + ); + const hasDefaulElasticsearchOutputDefined = + configToValidate.agents?.elasticsearch?.hosts?.length ?? 0 > 0; + + if (hasDefaulElasticsearchOutputDefined && hasDefaultPreconfiguredOuputs) { + return 'xpack.fleet.agents.elasticsearch.hosts should not be used when defining default outputs in xpack.fleet.outputs, please remove it.'; + } + }, + } + ), }; export type FleetConfigType = TypeOf; From 1c427a4a1e929054347c57a73974544d8ae18f2e Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Mon, 25 Sep 2023 13:09:30 -0700 Subject: [PATCH 33/45] Edit defaultModel generative AI connector description (#166405) --- .../connectors/action-types/gen-ai.asciidoc | 9 +++++---- .../connectors/images/gen-ai-connector.png | Bin 250790 -> 227205 bytes .../connector_types/gen_ai/constants.tsx | 13 +------------ .../connector_types/gen_ai/translations.ts | 5 ++--- 4 files changed, 8 insertions(+), 19 deletions(-) diff --git a/docs/management/connectors/action-types/gen-ai.asciidoc b/docs/management/connectors/action-types/gen-ai.asciidoc index 5e1b3553309ac..6388a483e7fc3 100644 --- a/docs/management/connectors/action-types/gen-ai.asciidoc +++ b/docs/management/connectors/action-types/gen-ai.asciidoc @@ -27,10 +27,11 @@ image::management/connectors/images/gen-ai-connector.png[Generative AI connector Generative AI connectors have the following configuration properties: -Name:: The name of the connector. -API Provider:: The OpenAI API provider, either OpenAI or Azure OpenAI. -API URL:: The OpenAI request URL. -API Key:: The OpenAI or Azure OpenAI API key for authentication. +Name:: The name of the connector. +OpenAI provider:: The OpenAI API provider, either OpenAI or Azure OpenAI. +URL:: The OpenAI request URL. +Default model:: (optional) The default model to use for requests. This option is available only when the provider is `OpenAI`. +API key:: The OpenAI or Azure OpenAI API key for authentication. [float] [[gen-ai-action-configuration]] diff --git a/docs/management/connectors/images/gen-ai-connector.png b/docs/management/connectors/images/gen-ai-connector.png index e84205723d7cdc3021a407feaa7991066b05cff9..4c737414d4e728216fa4f3b67c0041552514e3ef 100644 GIT binary patch literal 227205 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�|;SGQQfI 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�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

    X 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 IF>reDUugAw9smFU literal 250790 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 TUWSkNbM=zdFQ}hyJp6wE0M4N> diff --git a/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/constants.tsx b/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/constants.tsx index fc06a88fc91fb..ab7f18e2be00f 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/constants.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/constants.tsx @@ -58,19 +58,8 @@ export const openAiConfig: ConfigFieldSchema[] = [ label: i18n.DEFAULT_MODEL_LABEL, helpText: ( - {`${i18n.OPEN_AI} ${i18n.DOCUMENTATION}`} - - ), - }} /> ), defaultValue: DEFAULT_OPENAI_MODEL, diff --git a/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/translations.ts index a407413faa791..ef6ccd07d386b 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/translations.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/translations.ts @@ -15,7 +15,7 @@ export const API_URL_LABEL = i18n.translate( ); export const API_KEY_LABEL = i18n.translate('xpack.stackConnectors.components.genAi.apiKeySecret', { - defaultMessage: 'API Key', + defaultMessage: 'API key', }); export const DEFAULT_MODEL_LABEL = i18n.translate( @@ -28,8 +28,7 @@ export const DEFAULT_MODEL_LABEL = i18n.translate( export const DEFAULT_MODEL_TOOLTIP_CONTENT = i18n.translate( 'xpack.stackConnectors.components.genAi.defaultModelTooltipContent', { - defaultMessage: - 'The model can be set on a per request basis by including a "model" parameter in the request body. If no model is provided, the fallback will be the default model.', + defaultMessage: 'If a request does not include a model, it uses the default.', } ); From 3043bed9623c4b18cd32a18ab47f8a38c5243ba3 Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Mon, 25 Sep 2023 21:11:12 +0100 Subject: [PATCH 34/45] [Serverless Search] Serverless Getting Started UI Polish (#167118) Fixes a long list of julian's UI bugs. Tested on both stateful and serverless. See videos on visual fixes. https://github.com/elastic/kibana/assets/49480/1a450bf6-7477-40a4-a020-a5172b56ef4c https://github.com/elastic/kibana/assets/49480/92b40ecd-d888-4fd6-af91-045e81a1843f Things to note: - I had to adjust the asset path here as locally on main the images were broken (the header for example). --- .../components/code_box.tsx | 5 +- .../components/github_link.tsx | 2 +- .../components/ingest_data.tsx | 1 + .../components/install_client.tsx | 17 +--- .../components/integrations_panel.tsx | 47 +++++----- .../components/overview_panel.tsx | 23 ++--- .../components/try_in_console_button.tsx | 2 +- packages/kbn-search-api-panels/index.tsx | 89 ++++++++++--------- .../components/api_key/api_key.tsx | 5 +- .../application/components/overview.scss | 4 + .../application/components/overview.tsx | 2 +- 11 files changed, 99 insertions(+), 98 deletions(-) diff --git a/packages/kbn-search-api-panels/components/code_box.tsx b/packages/kbn-search-api-panels/components/code_box.tsx index ca3dd4d8b52c5..08fdd4cdf33ab 100644 --- a/packages/kbn-search-api-panels/components/code_box.tsx +++ b/packages/kbn-search-api-panels/components/code_box.tsx @@ -87,7 +87,7 @@ export const CodeBox: React.FC = ({ return ( - + = ({ {(copy) => ( - + {i18n.translate('searchApiPanels.welcomeBanner.codeBox.copyButtonLabel', { defaultMessage: 'Copy', })} @@ -127,6 +127,7 @@ export const CodeBox: React.FC = ({ transparentBackground fontSize="m" language={languageType || selectedLanguage.languageStyling || selectedLanguage.id} + overflowHeight={500} > {codeSnippet} diff --git a/packages/kbn-search-api-panels/components/github_link.tsx b/packages/kbn-search-api-panels/components/github_link.tsx index d0b41e21daeaf..9f5a2ee700c1b 100644 --- a/packages/kbn-search-api-panels/components/github_link.tsx +++ b/packages/kbn-search-api-panels/components/github_link.tsx @@ -18,7 +18,7 @@ export const GithubLink: React.FC<{ return ( - + diff --git a/packages/kbn-search-api-panels/components/ingest_data.tsx b/packages/kbn-search-api-panels/components/ingest_data.tsx index d25f7a74d05e3..0b0e11b13618d 100644 --- a/packages/kbn-search-api-panels/components/ingest_data.tsx +++ b/packages/kbn-search-api-panels/components/ingest_data.tsx @@ -93,6 +93,7 @@ export const IngestData: React.FC = ({ defaultMessage: 'Ingest data', })} > + = ({ /> - - - - {i18n.translate('searchApiPanels.welcomeBanner.apiCallout.content', { - defaultMessage: - 'Console enables you to call Elasticsearch and Kibana REST APIs directly, without needing to install a language client.', - })} - - ); return ( diff --git a/packages/kbn-search-api-panels/components/integrations_panel.tsx b/packages/kbn-search-api-panels/components/integrations_panel.tsx index 6f612be4dd101..dc4c472477578 100644 --- a/packages/kbn-search-api-panels/components/integrations_panel.tsx +++ b/packages/kbn-search-api-panels/components/integrations_panel.tsx @@ -35,20 +35,19 @@ export const IntegrationsPanel: React.FC = ({ return ( - + - +

    {i18n.translate('searchApiPanels.welcomeBanner.ingestData.logstashTitle', { defaultMessage: 'Logstash', })}

    - - +

    {i18n.translate('searchApiPanels.welcomeBanner.ingestData.logstashDescription', { @@ -57,16 +56,16 @@ export const IntegrationsPanel: React.FC = ({ })}

    - - - + + + {LEARN_MORE_LABEL} - + = ({ - + - +

    {i18n.translate('searchApiPanels.welcomeBanner.ingestData.beatsTitle', { defaultMessage: 'Beats', })}

    - + {i18n.translate('searchApiPanels.welcomeBanner.ingestData.beatsDescription', { defaultMessage: 'Lightweight, single-purpose data shippers for Elasticsearch. Use Beats to send operational data from your servers.', })} - - - + + + {LEARN_MORE_LABEL} - + @@ -119,36 +118,36 @@ export const IntegrationsPanel: React.FC = ({ - - + + - +

    {i18n.translate('searchApiPanels.welcomeBanner.ingestData.connectorsTitle', { defaultMessage: 'Connector Client', })}

    - + {i18n.translate('searchApiPanels.welcomeBanner.ingestData.connectorsDescription', { defaultMessage: 'Specialized integrations for syncing data from third-party sources to Elasticsearch. Use Elastic Connectors to sync content from a range of databases and object stores.', })} - - - + + + {LEARN_MORE_LABEL} - + = ({ return ( <> - + {leftPanelContent && {leftPanelContent}} - - + +

    {title}

    - + {description && {description}} {children} {links && links.length > 0 ? ( @@ -59,11 +59,14 @@ export const OverviewPanel: React.FC = ({
    {links.map(({ label, href }, index) => ( - - - {label} - - + + + + {label} + + + + ))} ) : null} diff --git a/packages/kbn-search-api-panels/components/try_in_console_button.tsx b/packages/kbn-search-api-panels/components/try_in_console_button.tsx index 35f6ef5d00184..93012c58a036d 100644 --- a/packages/kbn-search-api-panels/components/try_in_console_button.tsx +++ b/packages/kbn-search-api-panels/components/try_in_console_button.tsx @@ -40,7 +40,7 @@ export const TryInConsoleButton = ({ if (!consolePreviewLink) return null; return ( - + = ({ image, showDescription = true, }) => ( - - - {/* Reversing column direction here so screenreaders keep h1 as the first element */} - - - -

    - {i18n.translate('searchApiPanels.welcomeBanner.header.title', { - defaultMessage: 'Get started with Elasticsearch', - })} -

    -
    -
    - {Boolean(user) && ( + <> + + + + {/* Reversing column direction here so screenreaders keep h1 as the first element */} + - -

    - {user - ? i18n.translate('searchApiPanels.welcomeBanner.header.greeting.customTitle', { - defaultMessage: 'Hi {name}!', - values: { name: user.full_name || user.username }, - }) - : i18n.translate('searchApiPanels.welcomeBanner.header.greeting.defaultTitle', { - defaultMessage: 'Hi!', - })} -

    + +

    + {i18n.translate('searchApiPanels.welcomeBanner.header.title', { + defaultMessage: 'Get started with Elasticsearch', + })} +

    + {Boolean(user) && ( + + +

    + {user + ? i18n.translate('searchApiPanels.welcomeBanner.header.greeting.customTitle', { + defaultMessage: 'Hi {name}!', + values: { name: user.full_name || user.username }, + }) + : i18n.translate('searchApiPanels.welcomeBanner.header.greeting.defaultTitle', { + defaultMessage: 'Hi!', + })} +

    +
    +
    + )} +
    + + {showDescription && ( + + {i18n.translate('searchApiPanels.welcomeBanner.header.description', { + defaultMessage: + "Set up your programming language client, ingest some data, and you'll be ready to start searching within minutes.", + })} + )} -
    - - {showDescription && ( - - {i18n.translate('searchApiPanels.welcomeBanner.header.description', { - defaultMessage: - "Set up your programming language client, ingest some data, and you'll be ready to start searching within minutes.", - })} - - )} - -
    +
    - - - -
    + + + +
    + + ); diff --git a/x-pack/plugins/serverless_search/public/application/components/api_key/api_key.tsx b/x-pack/plugins/serverless_search/public/application/components/api_key/api_key.tsx index 671f1c1ff8cf1..5e9758e134b2a 100644 --- a/x-pack/plugins/serverless_search/public/application/components/api_key/api_key.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/api_key/api_key.tsx @@ -86,6 +86,7 @@ export const ApiKeyPanel = ({ setClientApiKey }: { setClientApiKey: (value: stri })}
    + {i18n.translate('xpack.serverlessSearch.apiKey.panel.description', { defaultMessage: @@ -94,8 +95,8 @@ export const ApiKeyPanel = ({ setClientApiKey }: { setClientApiKey: (value: stri - - + + {
    {i18n.translate('xpack.serverlessSearch.cloudIdDetails.url.title', { - defaultMessage: 'Cloud URL', + defaultMessage: 'Elasticsearch Endpoint', })}
    From 7a9a916260f7a12e83bfc4e7c6647994577f1d61 Mon Sep 17 00:00:00 2001 From: "Quynh Nguyen (Quinn)" <43350163+qn895@users.noreply.github.com> Date: Mon, 25 Sep 2023 17:10:52 -0500 Subject: [PATCH 35/45] [ML] Hide Exclude frozen data tier option in Transforms creation page (#166622) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/full_time_range_selector.tsx | 1 + x-pack/plugins/transform/public/app/app.tsx | 11 ++- .../public/app/mount_management_section.ts | 6 +- .../step_define/step_define_form.tsx | 3 + .../transform_list/expanded_row.tsx | 75 +++++++++---------- .../expanded_row_messages_pane.tsx | 8 +- .../transform_list/transforms_stats_bar.tsx | 16 ++-- .../transform_management_section.tsx | 10 +-- .../public/app/serverless_context.tsx | 23 ++++-- 9 files changed, 84 insertions(+), 69 deletions(-) diff --git a/x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx b/x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx index e3e5a1de3d65f..fcf4622e87cc0 100644 --- a/x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx +++ b/x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx @@ -98,6 +98,7 @@ export const FullTimeRangeSelector: FC = (props) => apiPath, hideFrozenDataTierChoice = false, } = props; + const { http, notifications: { toasts }, diff --git a/x-pack/plugins/transform/public/app/app.tsx b/x-pack/plugins/transform/public/app/app.tsx index 2812475f7f87a..21d1ca2b1b6b6 100644 --- a/x-pack/plugins/transform/public/app/app.tsx +++ b/x-pack/plugins/transform/public/app/app.tsx @@ -20,7 +20,10 @@ import { AppDependencies } from './app_dependencies'; import { CloneTransformSection } from './sections/clone_transform'; import { CreateTransformSection } from './sections/create_transform'; import { TransformManagementSection } from './sections/transform_management'; -import { ServerlessContextProvider } from './serverless_context'; +import { + EnabledFeaturesContextProvider, + type TransformEnabledFeatures, +} from './serverless_context'; export const App: FC<{ history: ScopedHistory }> = ({ history }) => ( @@ -41,7 +44,7 @@ export const App: FC<{ history: ScopedHistory }> = ({ history }) => ( export const renderApp = ( element: HTMLElement, appDependencies: AppDependencies, - isServerless: boolean + enabledFeatures: TransformEnabledFeatures ) => { const I18nContext = appDependencies.i18n.Context; @@ -60,9 +63,9 @@ export const renderApp = ( - + - + diff --git a/x-pack/plugins/transform/public/app/mount_management_section.ts b/x-pack/plugins/transform/public/app/mount_management_section.ts index 86b2a297ed636..f00596e1326b4 100644 --- a/x-pack/plugins/transform/public/app/mount_management_section.ts +++ b/x-pack/plugins/transform/public/app/mount_management_section.ts @@ -9,6 +9,7 @@ import { CoreSetup } from '@kbn/core/public'; import { ManagementAppMountParams } from '@kbn/management-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; +import { type TransformEnabledFeatures } from './serverless_context'; import { PluginsDependencies } from '../plugin'; import { getMlSharedImports } from '../shared_imports'; @@ -93,7 +94,10 @@ export async function mountManagementSection( contentManagement, }; - const unmountAppCallback = renderApp(element, appDependencies, isServerless); + const enabledFeatures: TransformEnabledFeatures = { + showNodeInfo: !isServerless, + }; + const unmountAppCallback = renderApp(element, appDependencies, enabledFeatures); return () => { docTitle.reset(); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx index 246460d11d3ee..e9326ae195015 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx @@ -35,6 +35,7 @@ import { import { useStorage } from '@kbn/ml-local-storage'; import { useUrlState } from '@kbn/ml-url-state'; +import { useEnabledFeatures } from '../../../../serverless_context'; import { PivotAggDict } from '../../../../../../common/types/pivot_aggs'; import { PivotGroupByDict } from '../../../../../../common/types/pivot_group_by'; import { TRANSFORM_FUNCTION } from '../../../../../../common/constants'; @@ -112,6 +113,7 @@ export const StepDefineForm: FC = React.memo((props) => { ); const toastNotifications = useToastNotifications(); const stepDefineForm = useStepDefineForm(props); + const { showNodeInfo } = useEnabledFeatures(); const { advancedEditorConfig } = stepDefineForm.advancedPivotEditor.state; const { @@ -353,6 +355,7 @@ export const StepDefineForm: FC = React.memo((props) => { query={undefined} disabled={false} timefilter={timefilter} + hideFrozenDataTierChoice={!showNodeInfo} />
    diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.tsx index c43e3d096f32b..079b3f72b59bd 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.tsx @@ -5,18 +5,18 @@ * 2.0. */ -import React, { FC, useMemo } from 'react'; -import { css } from '@emotion/react'; +import React, { useMemo, type FC } from 'react'; import moment from 'moment-timezone'; +import { css } from '@emotion/react'; import { EuiButtonEmpty, EuiLoadingSpinner, - EuiTabbedContent, EuiFlexGroup, useEuiTheme, EuiCallOut, EuiFlexItem, + EuiTabbedContent, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -25,8 +25,8 @@ import { stringHash } from '@kbn/ml-string-hash'; import { isDefined } from '@kbn/ml-is-defined'; import { FormattedMessage } from '@kbn/i18n-react'; +import { useEnabledFeatures } from '../../../../serverless_context'; import { isTransformListRowWithStats } from '../../../../common/transform_list'; -import { useIsServerless } from '../../../../serverless_context'; import { TransformHealthAlertRule } from '../../../../../../common/types/alerting'; import { TransformListRow } from '../../../../common'; @@ -86,39 +86,13 @@ const NoStatsFallbackTabContent = ({ }; export const ExpandedRow: FC = ({ item, onAlertEdit, transformsStatsLoading }) => { - const hideNodeInfo = useIsServerless(); + const { showNodeInfo } = useEnabledFeatures(); const stateItems: Item[] = []; stateItems.push({ title: 'ID', description: item.id, }); - if (isTransformListRowWithStats(item)) { - stateItems.push({ - title: 'state', - description: item.stats.state, - }); - - if (!hideNodeInfo && item.stats.node !== undefined) { - stateItems.push({ - title: 'node.name', - description: item.stats.node.name, - }); - } - if (item.stats.health !== undefined) { - stateItems.push({ - title: 'health', - description: , - }); - } - } - - const state: SectionConfig = { - title: 'State', - items: stateItems, - position: 'right', - }; - const configItems = useMemo(() => { const configs: Item[] = [ { @@ -166,14 +140,25 @@ export const ExpandedRow: FC = ({ item, onAlertEdit, transformsStatsLoadi // eslint-disable-next-line react-hooks/exhaustive-deps }, [item?.config]); - const general: SectionConfig = { - title: 'General', - items: configItems, - position: 'left', - }; - const checkpointingItems: Item[] = []; if (isTransformListRowWithStats(item)) { + stateItems.push({ + title: 'state', + description: item.stats.state, + }); + if (showNodeInfo && item.stats.node !== undefined) { + stateItems.push({ + title: 'node.name', + description: item.stats.node.name, + }); + } + if (item.stats.health !== undefined) { + stateItems.push({ + title: 'health', + description: , + }); + } + if (item.stats.checkpointing.changes_last_detected_at !== undefined) { checkpointingItems.push({ title: 'changes_last_detected_at', @@ -238,6 +223,18 @@ export const ExpandedRow: FC = ({ item, onAlertEdit, transformsStatsLoadi } } + const state: SectionConfig = { + title: 'State', + items: stateItems, + position: 'right', + }; + + const general: SectionConfig = { + title: 'General', + items: configItems, + position: 'left', + }; + const alertRuleItems: Item[] | undefined = item.alerting_rules?.map((rule) => { return { title: ( @@ -274,7 +271,7 @@ export const ExpandedRow: FC = ({ item, onAlertEdit, transformsStatsLoadi const stats: SectionConfig = { title: 'Stats', - items: item.stats + items: isTransformListRowWithStats(item) ? Object.entries(item.stats.stats).map((s) => { return { title: s[0].toString(), description: getItemDescription(s[1]) }; }) @@ -315,7 +312,7 @@ export const ExpandedRow: FC = ({ item, onAlertEdit, transformsStatsLoadi defaultMessage: 'Stats', } ), - content: item.stats ? ( + content: isTransformListRowWithStats(item) ? ( ) : ( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx index 10c1a4f01dfb2..8124ecbb87182 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx @@ -19,7 +19,7 @@ import { import { euiLightVars as theme } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; -import { useIsServerless } from '../../../../serverless_context'; +import { useEnabledFeatures } from '../../../../serverless_context'; import { DEFAULT_MAX_AUDIT_MESSAGE_SIZE, TIME_FORMAT } from '../../../../../../common/constants'; import { TransformMessage } from '../../../../../../common/types/messages'; @@ -36,7 +36,7 @@ interface Sorting { } export const ExpandedRowMessagesPane: FC = ({ transformId }) => { - const hideNodeInfo = useIsServerless(); + const { showNodeInfo } = useEnabledFeatures(); const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); @@ -99,7 +99,7 @@ export const ExpandedRowMessagesPane: FC = ({ tran render: (timestamp: number) => formatDate(timestamp, TIME_FORMAT), sortable: true, }, - ...(!hideNodeInfo + ...(showNodeInfo ? [ { field: 'node_name', @@ -121,7 +121,7 @@ export const ExpandedRowMessagesPane: FC = ({ tran defaultMessage: 'Message', } ), - width: !hideNodeInfo ? '50%' : '70%', + width: showNodeInfo ? '50%' : '70%', }, ]; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx index ea85f705e46ef..bf1e07a18f20f 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx @@ -12,7 +12,7 @@ import { EuiButton, EuiCallOut, EuiLink, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useIsServerless } from '../../../../serverless_context'; +import { useEnabledFeatures } from '../../../../serverless_context'; import { TRANSFORM_MODE, TRANSFORM_STATE } from '../../../../../../common/constants'; import { TransformListRow } from '../../../../common'; @@ -21,10 +21,10 @@ import { useDocumentationLinks, useRefreshTransformList } from '../../../../hook import { StatsBar, TransformStatsBarStats } from '../stats_bar'; -function createTranformStats( +function createTransformStats( transformNodes: number, transformsList: TransformListRow[], - hideNodeInfo: boolean + showNodeInfo: boolean ): TransformStatsBarStats { const transformStats: TransformStatsBarStats = { total: { @@ -64,7 +64,7 @@ function createTranformStats( }, }; - if (!hideNodeInfo) { + if (showNodeInfo) { transformStats.nodes = { label: i18n.translate('xpack.transform.statsBar.transformNodesLabel', { defaultMessage: 'Nodes', @@ -125,19 +125,19 @@ export const TransformStatsBar: FC = ({ transformNodes, transformsList, }) => { - const hideNodeInfo = useIsServerless(); + const { showNodeInfo } = useEnabledFeatures(); const refreshTransformList = useRefreshTransformList(); const { esNodeRoles } = useDocumentationLinks(); - const transformStats: TransformStatsBarStats = createTranformStats( + const transformStats: TransformStatsBarStats = createTransformStats( transformNodes, transformsList, - hideNodeInfo + showNodeInfo ); return ( <> - {!hideNodeInfo && transformNodes === 0 && ( + {showNodeInfo && transformNodes === 0 && ( <> { const { esTransform } = useDocumentationLinks(); - const hideNodeInfo = useIsServerless(); + const { showNodeInfo } = useEnabledFeatures(); const deleteTransforms = useDeleteTransforms(); @@ -92,7 +92,7 @@ export const TransformManagement: FC = () => { error: transformsErrorMessage, data: { transforms: transformsWithoutStats, transformIdsWithoutConfig }, } = useGetTransforms({ - enabled: !transformNodesInitialLoading && (transformNodes > 0 || hideNodeInfo), + enabled: !transformNodesInitialLoading && transformNodes > 0, }); const { @@ -100,7 +100,7 @@ export const TransformManagement: FC = () => { error: transformsStatsErrorMessage, data: transformsStats, } = useGetTransformsStats({ - enabled: !transformNodesInitialLoading && (transformNodes > 0 || hideNodeInfo), + enabled: !transformNodesInitialLoading && transformNodes > 0, }); const transforms: TransformListRow[] = useMemo(() => { @@ -224,7 +224,7 @@ export const TransformManagement: FC = () => { <> {unauthorizedTransformsWarning} - {!hideNodeInfo && transformNodesErrorMessage !== null && ( + {showNodeInfo && transformNodesErrorMessage !== null && ( = (props) => { - const { children, isServerless } = props; +export const EnabledFeaturesContextProvider: FC<{ enabledFeatures: TransformEnabledFeatures }> = ( + props +) => { + const { children, enabledFeatures } = props; return ( - {children} + + {children} + ); }; -export function useIsServerless() { - const context = useContext(ServerlessContext); +export function useEnabledFeatures() { + const context = useContext(EnabledFeaturesContext); return useMemo(() => { - return context.isServerless; + return context; }, [context]); } From d4bb52b8b2d64fb9c1a36716e7e2267f284fb5c3 Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Mon, 25 Sep 2023 16:19:25 -0600 Subject: [PATCH 36/45] [ML] Data Frame Analytics Trained models flyout: update horizontal steps size (#167095) ## Summary Related issue: https://github.com/elastic/kibana/issues/162831 - uses small size for EuiStepsHorizontal component image ### Checklist Delete any items that are not applicable to this PR. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/add_inference_pipeline_horizontal_steps.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/ml/public/application/components/ml_inference/components/add_inference_pipeline_horizontal_steps.tsx b/x-pack/plugins/ml/public/application/components/ml_inference/components/add_inference_pipeline_horizontal_steps.tsx index 9954ed8955259..2a34f6483c24d 100644 --- a/x-pack/plugins/ml/public/application/components/ml_inference/components/add_inference_pipeline_horizontal_steps.tsx +++ b/x-pack/plugins/ml/public/application/components/ml_inference/components/add_inference_pipeline_horizontal_steps.tsx @@ -113,6 +113,6 @@ export const AddInferencePipelineHorizontalSteps: FC = memo( navSteps[4].status = 'current'; break; } - return ; + return ; } ); From 1066eb3d593ce7ac9930e8d0d409d9f3b1af079b Mon Sep 17 00:00:00 2001 From: Catherine Liu Date: Mon, 25 Sep 2023 15:37:30 -0700 Subject: [PATCH 37/45] =?UTF-8?q?[Dashboard]=C2=A0Focus=20on=20a=20single?= =?UTF-8?q?=20panel=20(#165417)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../buttons/toolbar_button/toolbar_button.tsx | 17 ++- .../button_toolbar/src/popover/popover.tsx | 2 + .../controls_toolbar_button.tsx | 9 +- .../top_nav/dashboard_editing_toolbar.tsx | 14 ++- .../top_nav/dashboard_top_nav.tsx | 5 +- .../dashboard_app/top_nav/editor_menu.tsx | 4 +- .../component/grid/dashboard_grid.test.tsx | 29 ++++- .../component/grid/dashboard_grid.tsx | 8 +- .../grid/dashboard_grid_item.test.tsx | 116 ++++++++++++++++++ .../component/grid/dashboard_grid_item.tsx | 38 +++++- .../component/panel/_dashboard_panel.scss | 4 +- .../component/viewport/dashboard_viewport.tsx | 7 +- .../embeddable/dashboard_container.tsx | 10 +- .../state/dashboard_container_reducers.ts | 3 + .../public/dashboard_container/types.ts | 1 + .../panel_actions/track_overlays.ts | 6 +- .../embeddable_panel_context_menu.tsx | 5 +- .../open_lens_config/helpers.ts | 15 +-- 18 files changed, 250 insertions(+), 43 deletions(-) create mode 100644 src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.test.tsx diff --git a/packages/shared-ux/button_toolbar/src/buttons/toolbar_button/toolbar_button.tsx b/packages/shared-ux/button_toolbar/src/buttons/toolbar_button/toolbar_button.tsx index 34bd7db5e9dec..76adb41e237bd 100644 --- a/packages/shared-ux/button_toolbar/src/buttons/toolbar_button/toolbar_button.tsx +++ b/packages/shared-ux/button_toolbar/src/buttons/toolbar_button/toolbar_button.tsx @@ -20,7 +20,7 @@ type ToolbarButtonTypes = 'primary' | 'empty'; export interface Props extends Pick< EuiButtonPropsForButton, - 'onClick' | 'iconType' | 'iconSide' | 'size' | 'data-test-subj' + 'onClick' | 'iconType' | 'iconSide' | 'size' | 'data-test-subj' | 'isDisabled' > { label: string; type?: ToolbarButtonTypes; @@ -31,16 +31,23 @@ export const ToolbarButton: React.FunctionComponent = ({ type = 'empty', iconSide = 'left', size = 'm', + isDisabled, ...rest }) => { const euiTheme = useEuiTheme(); - const toolbarButtonStyleProps: EuiButtonPropsForButton = - type === 'primary' + const toolbarButtonStyleProps: EuiButtonPropsForButton = !isDisabled + ? type === 'primary' ? { color: 'primary', fill: true } - : { color: 'text', css: ToolbarButtonStyles(euiTheme).emptyButton }; + : { color: 'text', css: ToolbarButtonStyles(euiTheme).emptyButton } + : {}; return ( - + {label} ); diff --git a/packages/shared-ux/button_toolbar/src/popover/popover.tsx b/packages/shared-ux/button_toolbar/src/popover/popover.tsx index 89654e37c850a..25dff5c52250f 100644 --- a/packages/shared-ux/button_toolbar/src/popover/popover.tsx +++ b/packages/shared-ux/button_toolbar/src/popover/popover.tsx @@ -35,6 +35,7 @@ export const ToolbarPopover = ({ iconType, size = 'm', children, + isDisabled, ...popover }: Props) => { const [isOpen, setIsOpen] = useState(false); @@ -46,6 +47,7 @@ export const ToolbarPopover = ({ ); 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 bcb193f9cc1e3..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 @@ -17,7 +17,13 @@ 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({ controlGroup }: { controlGroup: ControlGroupContainer }) { +export function ControlsToolbarButton({ + controlGroup, + isDisabled, +}: { + controlGroup: ControlGroupContainer; + isDisabled?: boolean; +}) { const { euiTheme } = useEuiTheme(); return ( @@ -30,6 +36,7 @@ export function ControlsToolbarButton({ controlGroup }: { controlGroup: ControlG size="s" iconType="controlsHorizontal" data-test-subj="dashboard-controls-menu-button" + isDisabled={isDisabled} > {({ closePopover }: { closePopover: () => void }) => ( , + , dashboard.addFromLibrary()} size="s" data-test-subj="dashboardAddFromLibraryButton" + isDisabled={isDisabled} />, ]; if (dashboard.controlGroup) { - extraButtons.push(); + extraButtons.push( + + ); } return ( @@ -128,6 +135,7 @@ export function DashboardEditingToolbar() { primaryButton: ( state.componentState.fullScreenMode); const savedQueryId = dashboard.select((state) => state.componentState.savedQueryId); const lastSavedId = dashboard.select((state) => state.componentState.lastSavedId); + const focusedPanelId = dashboard.select((state) => state.componentState.focusedPanelId); const managed = dashboard.select((state) => state.componentState.managed); const viewMode = dashboard.select((state) => state.explicitInput.viewMode); @@ -323,7 +324,9 @@ export function DashboardTopNav({ embedSettings, redirectTo }: DashboardTopNavPr setIsLabsShown(false)} /> ) : null} - {viewMode === ViewMode.EDIT ? : null} + {viewMode === ViewMode.EDIT ? ( + + ) : null}
  • ); diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx index 9512d837e61be..d2b6470650caa 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx @@ -24,6 +24,7 @@ import { pluginServices } from '../../services/plugin_services'; import { DASHBOARD_APP_ID } from '../../dashboard_constants'; interface Props { + isDisabled?: boolean; /** Handler for creating new visualization of a specified type */ createNewVisType: (visType: BaseVisType | VisTypeAlias) => () => void; /** Handler for creating a new embeddable of a specified type */ @@ -43,7 +44,7 @@ interface UnwrappedEmbeddableFactory { isEditable: boolean; } -export const EditorMenu = ({ createNewVisType, createNewEmbeddable }: Props) => { +export const EditorMenu = ({ createNewVisType, createNewEmbeddable, isDisabled }: Props) => { const { embeddable, visualizations: { @@ -273,6 +274,7 @@ export const EditorMenu = ({ createNewVisType, createNewEmbeddable }: Props) => label={i18n.translate('dashboard.solutionToolbar.editorMenuButtonLabel', { defaultMessage: 'Add panel', })} + isDisabled={isDisabled} size="s" iconType="plusInCircle" panelPaddingSize="none" 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 be21a9ba6645e..6c8a123d19588 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 @@ -21,12 +21,19 @@ jest.mock('./dashboard_grid_item', () => { // eslint-disable-next-line @typescript-eslint/no-var-requires DashboardGridItem: require('react').forwardRef( (props: DashboardGridItemProps, ref: HTMLDivElement) => { - const className = + const className = `${ props.expandedPanelId === undefined ? 'regularPanel' : props.expandedPanelId === props.id ? 'expandedPanel' - : 'hiddenPanel'; + : 'hiddenPanel' + } ${ + props.focusedPanelId + ? props.focusedPanelId === props.id + ? 'focusedPanel' + : 'blurredPanel' + : '' + }`; return (
    mockDashboardGridItem @@ -101,3 +108,21 @@ test('DashboardGrid renders expanded panel', async () => { expect(component.find('#mockDashboardGridItem_1').hasClass('regularPanel')).toBe(true); expect(component.find('#mockDashboardGridItem_2').hasClass('regularPanel')).toBe(true); }); + +test('DashboardGrid renders focused panel', async () => { + 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. + expect(component.find('GridItem').length).toBe(2); + + expect(component.find('#mockDashboardGridItem_1').hasClass('blurredPanel')).toBe(true); + expect(component.find('#mockDashboardGridItem_2').hasClass('focusedPanel')).toBe(true); + + dashboardContainer.setFocusedPanelId(undefined); + component.update(); + expect(component.find('GridItem').length).toBe(2); + + expect(component.find('#mockDashboardGridItem_1').hasClass('blurredPanel')).toBe(false); + expect(component.find('#mockDashboardGridItem_2').hasClass('focusedPanel')).toBe(false); +}); diff --git a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid.tsx b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid.tsx index 12cd26df28f18..e496939e8ade0 100644 --- a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid.tsx +++ b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid.tsx @@ -30,6 +30,7 @@ export const DashboardGrid = ({ viewportWidth }: { viewportWidth: number }) => { const viewMode = dashboard.select((state) => state.explicitInput.viewMode); const useMargins = dashboard.select((state) => state.explicitInput.useMargins); const expandedPanelId = dashboard.select((state) => state.componentState.expandedPanelId); + const focusedPanelId = dashboard.select((state) => state.componentState.focusedPanelId); const animatePanelTransforms = dashboard.select( (state) => state.componentState.animatePanelTransforms ); @@ -78,11 +79,12 @@ export const DashboardGrid = ({ viewportWidth }: { viewportWidth: number }) => { index={index + 1} type={type} expandedPanelId={expandedPanelId} + focusedPanelId={focusedPanelId} onPanelStatusChange={onPanelStatusChange} /> ); }); - }, [expandedPanelId, onPanelStatusChange, panels, panelsInOrder]); + }, [expandedPanelId, onPanelStatusChange, panels, panelsInOrder, focusedPanelId]); const onLayoutChange = useCallback( (newLayout: Array) => { @@ -127,8 +129,8 @@ export const DashboardGrid = ({ viewportWidth }: { viewportWidth: number }) => { breakpoints={breakpoints} onDragStop={onLayoutChange} onResizeStop={onLayoutChange} - isResizable={!expandedPanelId} - isDraggable={!expandedPanelId} + isResizable={!expandedPanelId && !focusedPanelId} + isDraggable={!expandedPanelId && !focusedPanelId} rowHeight={DASHBOARD_GRID_HEIGHT} margin={useMargins ? [DASHBOARD_MARGIN_SIZE, DASHBOARD_MARGIN_SIZE] : [0, 0]} draggableHandle={'.embPanel--dragHandle'} diff --git a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.test.tsx b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.test.tsx new file mode 100644 index 0000000000000..fa26677ba1f17 --- /dev/null +++ b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.test.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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; + +import { mountWithIntl } from '@kbn/test-jest-helpers'; +import { CONTACT_CARD_EMBEDDABLE } from '@kbn/embeddable-plugin/public/lib/test_samples/embeddables'; + +import { buildMockDashboard } from '../../../mocks'; +import { Item, Props as DashboardGridItemProps } from './dashboard_grid_item'; +import { DashboardContainerContext } from '../../embeddable/dashboard_container'; + +jest.mock('@kbn/embeddable-plugin/public', () => { + const original = jest.requireActual('@kbn/embeddable-plugin/public'); + + return { + ...original, + EmbeddablePanel: (props: DashboardGridItemProps) => { + return ( +
    + mockEmbeddablePanel +
    + ); + }, + }; +}); + +const createAndMountDashboardGridItem = (props: DashboardGridItemProps) => { + const panels = { + '1': { + gridData: { x: 0, y: 0, w: 6, h: 6, i: '1' }, + type: CONTACT_CARD_EMBEDDABLE, + explicitInput: { id: '1' }, + }, + '2': { + gridData: { x: 6, y: 6, w: 6, h: 6, i: '2' }, + type: CONTACT_CARD_EMBEDDABLE, + explicitInput: { id: '2' }, + }, + }; + const dashboardContainer = buildMockDashboard({ panels }); + + const component = mountWithIntl( + + + + ); + return { dashboardContainer, component }; +}; + +test('renders Item', async () => { + const { component } = createAndMountDashboardGridItem({ + id: '1', + key: '1', + type: CONTACT_CARD_EMBEDDABLE, + }); + const panelElements = component.find('.embedPanel'); + expect(panelElements.length).toBe(1); + + expect(component.find('#panel-1').hasClass('dshDashboardGrid__item--expanded')).toBe(false); + expect(component.find('#panel-1').hasClass('dshDashboardGrid__item--hidden')).toBe(false); + + expect(component.find('#panel-1').hasClass('dshDashboardGrid__item--focused')).toBe(false); + expect(component.find('#panel-1').hasClass('dshDashboardGrid__item--blurred')).toBe(false); +}); + +test('renders expanded panel', async () => { + const { component } = createAndMountDashboardGridItem({ + id: '1', + key: '1', + type: CONTACT_CARD_EMBEDDABLE, + expandedPanelId: '1', + }); + expect(component.find('#panel-1').hasClass('dshDashboardGrid__item--expanded')).toBe(true); + expect(component.find('#panel-1').hasClass('dshDashboardGrid__item--hidden')).toBe(false); +}); + +test('renders hidden panel', async () => { + const { component } = createAndMountDashboardGridItem({ + id: '1', + key: '1', + type: CONTACT_CARD_EMBEDDABLE, + expandedPanelId: '2', + }); + expect(component.find('#panel-1').hasClass('dshDashboardGrid__item--expanded')).toBe(false); + expect(component.find('#panel-1').hasClass('dshDashboardGrid__item--hidden')).toBe(true); +}); + +test('renders focused panel', async () => { + const { component } = createAndMountDashboardGridItem({ + id: '1', + key: '1', + type: CONTACT_CARD_EMBEDDABLE, + focusedPanelId: '1', + }); + + expect(component.find('#panel-1').hasClass('dshDashboardGrid__item--focused')).toBe(true); + expect(component.find('#panel-1').hasClass('dshDashboardGrid__item--blurred')).toBe(false); +}); + +test('renders blurred panel', async () => { + const { component } = createAndMountDashboardGridItem({ + id: '1', + key: '1', + type: CONTACT_CARD_EMBEDDABLE, + focusedPanelId: '2', + }); + + expect(component.find('#panel-1').hasClass('dshDashboardGrid__item--focused')).toBe(false); + expect(component.find('#panel-1').hasClass('dshDashboardGrid__item--blurred')).toBe(true); +}); diff --git a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx index 9da737a5e7446..9eb12379741ab 100644 --- a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx +++ b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx @@ -12,6 +12,7 @@ import classNames from 'classnames'; import { EmbeddablePhaseEvent, EmbeddablePanel, ViewMode } from '@kbn/embeddable-plugin/public'; +import { css } from '@emotion/react'; import { DashboardPanelState } from '../../../../common'; import { pluginServices } from '../../../services/plugin_services'; import { useDashboardContainer } from '../../embeddable/dashboard_container'; @@ -22,14 +23,14 @@ export interface Props extends DivProps { id: DashboardPanelState['explicitInput']['id']; index?: number; type: DashboardPanelState['type']; - focusedPanelId?: string; expandedPanelId?: string; + focusedPanelId?: string; key: string; isRenderable?: boolean; onPanelStatusChange?: (info: EmbeddablePhaseEvent) => void; } -const Item = React.forwardRef( +export const Item = React.forwardRef( ( { expandedPanelId, @@ -43,7 +44,6 @@ const Item = React.forwardRef( // https://github.com/react-grid-layout/react-grid-layout/issues/1241#issuecomment-658306889 children, className, - style, ...rest }, ref @@ -54,9 +54,13 @@ const Item = React.forwardRef( const expandPanel = expandedPanelId !== undefined && expandedPanelId === id; const hidePanel = expandedPanelId !== undefined && expandedPanelId !== id; + const focusPanel = focusedPanelId !== undefined && focusedPanelId === id; + const blurPanel = focusedPanelId !== undefined && focusedPanelId !== id; const classes = classNames({ 'dshDashboardGrid__item--expanded': expandPanel, 'dshDashboardGrid__item--hidden': hidePanel, + 'dshDashboardGrid__item--focused': focusPanel, + 'dshDashboardGrid__item--blurred': blurPanel, // eslint-disable-next-line @typescript-eslint/naming-convention printViewport__vis: container.getInput().viewMode === ViewMode.PRINT, }); @@ -69,12 +73,29 @@ const Item = React.forwardRef( if (highlightPanelId === id) { container.highlightPanel(ref.current); } + + ref.current.querySelectorAll('*').forEach((e) => { + if (blurPanel) { + // remove blurred panels and nested elements from tab order + e.setAttribute('tabindex', '-1'); + } else { + // restore tab order + e.removeAttribute('tabindex'); + } + }); } - }, [id, container, scrollToPanelId, highlightPanelId, ref]); + }, [id, container, scrollToPanelId, highlightPanelId, ref, blurPanel]); + + const focusStyles = blurPanel + ? css` + pointer-events: none; + opacity: 0.25; + ` + : css``; return (
    ((props, const { settings: { isProjectEnabledInLabs }, } = pluginServices.getServices(); + const container = useDashboardContainer(); + const focusedPanelId = container.select((state) => state.componentState.focusedPanelId); const dashboard = useDashboardContainer(); const isPrintMode = dashboard.select((state) => state.explicitInput.viewMode) === ViewMode.PRINT; - const isEnabled = !isPrintMode && isProjectEnabledInLabs('labs:dashboard:deferBelowFold'); + const isEnabled = + !isPrintMode && + isProjectEnabledInLabs('labs:dashboard:deferBelowFold') && + (!focusedPanelId || focusedPanelId === props.id); return isEnabled ? : ; }); diff --git a/src/plugins/dashboard/public/dashboard_container/component/panel/_dashboard_panel.scss b/src/plugins/dashboard/public/dashboard_container/component/panel/_dashboard_panel.scss index 33aab22fb8b8b..eb448412d1ae4 100644 --- a/src/plugins/dashboard/public/dashboard_container/component/panel/_dashboard_panel.scss +++ b/src/plugins/dashboard/public/dashboard_container/component/panel/_dashboard_panel.scss @@ -23,7 +23,9 @@ // Remove border color unless in editing mode .dshLayout-withoutMargins:not(.dshLayout--editing), -.dshDashboardGrid__item--expanded { +.dshDashboardGrid__item--expanded, +.dshDashboardGrid__item--blurred, +.dshDashboardGrid__item--focused { .embPanel { border-color: transparent; } 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 15219455b17b2..d1931d7ed3e61 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 @@ -20,13 +20,13 @@ import { pluginServices } from '../../../services/plugin_services'; import { useDashboardContainer } from '../../embeddable/dashboard_container'; import { DashboardEmptyScreen } from '../empty_screen/dashboard_empty_screen'; -export const useDebouncedWidthObserver = (wait = 250) => { +export const useDebouncedWidthObserver = (skipDebounce = false, wait = 100) => { const [width, setWidth] = useState(0); const onWidthChange = useMemo(() => debounce(setWidth, wait), [wait]); const { ref } = useResizeObserver({ onResize: (dimensions) => { if (dimensions.width) { - if (width === 0) setWidth(dimensions.width); + if (width === 0 || skipDebounce) setWidth(dimensions.width); if (dimensions.width !== width) onWidthChange(dimensions.width); } }, @@ -58,10 +58,11 @@ export const DashboardViewportComponent = () => { const viewMode = dashboard.select((state) => state.explicitInput.viewMode); const dashboardTitle = dashboard.select((state) => state.explicitInput.title); const description = dashboard.select((state) => state.explicitInput.description); + const focusedPanelId = dashboard.select((state) => state.componentState.focusedPanelId); const expandedPanelId = dashboard.select((state) => state.componentState.expandedPanelId); const controlsEnabled = isProjectEnabledInLabs('labs:dashboard:dashboardControls'); - const { ref: resizeRef, width: viewportWidth } = useDebouncedWidthObserver(); + const { ref: resizeRef, width: viewportWidth } = useDebouncedWidthObserver(!!focusedPanelId); const classes = classNames({ dshDashboardViewport: true, 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 ef09d9fd9504d..2a618ad6a04d4 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx @@ -434,14 +434,18 @@ export class DashboardContainer extends Container { + public openOverlay = (ref: OverlayRef, options?: { focusedPanelId?: string }) => { this.clearOverlays(); this.dispatch.setHasOverlays(true); this.overlayRef = ref; + if (options?.focusedPanelId) { + this.setFocusedPanelId(options?.focusedPanelId); + } }; public clearOverlays = () => { this.dispatch.setHasOverlays(false); + this.dispatch.setFocusedPanelId(undefined); this.controlGroup?.closeAllFlyouts(); this.overlayRef?.close(); }; @@ -500,4 +504,8 @@ export class DashboardContainer extends Container { + this.dispatch.setFocusedPanelId(id); + }; } diff --git a/src/plugins/dashboard/public/dashboard_container/state/dashboard_container_reducers.ts b/src/plugins/dashboard/public/dashboard_container/state/dashboard_container_reducers.ts index 65660e1065f28..b0299ecfd47f1 100644 --- a/src/plugins/dashboard/public/dashboard_container/state/dashboard_container_reducers.ts +++ b/src/plugins/dashboard/public/dashboard_container/state/dashboard_container_reducers.ts @@ -239,6 +239,9 @@ export const dashboardContainerReducers = { setHighlightPanelId: (state: DashboardReduxState, action: PayloadAction) => { state.componentState.highlightPanelId = action.payload; }, + setFocusedPanelId: (state: DashboardReduxState, action: PayloadAction) => { + state.componentState.focusedPanelId = action.payload; + }, setAnimatePanelTransforms: ( state: DashboardReduxState, diff --git a/src/plugins/dashboard/public/dashboard_container/types.ts b/src/plugins/dashboard/public/dashboard_container/types.ts index dd01f643b99fc..b71876b1ea724 100644 --- a/src/plugins/dashboard/public/dashboard_container/types.ts +++ b/src/plugins/dashboard/public/dashboard_container/types.ts @@ -43,6 +43,7 @@ export interface DashboardPublicState { managed?: boolean; scrollToPanelId?: string; highlightPanelId?: string; + focusedPanelId?: string; } export interface DashboardRenderPerformanceStats { diff --git a/src/plugins/embeddable/public/embeddable_panel/panel_actions/track_overlays.ts b/src/plugins/embeddable/public/embeddable_panel/panel_actions/track_overlays.ts index 28022e6ed1937..10633e557b52b 100644 --- a/src/plugins/embeddable/public/embeddable_panel/panel_actions/track_overlays.ts +++ b/src/plugins/embeddable/public/embeddable_panel/panel_actions/track_overlays.ts @@ -8,8 +8,12 @@ import { OverlayRef } from '@kbn/core-mount-utils-browser'; +interface TracksOverlaysOptions { + focusedPanelId?: string; +} + interface TracksOverlays { - openOverlay: (ref: OverlayRef) => void; + openOverlay: (ref: OverlayRef, options?: TracksOverlaysOptions) => void; clearOverlays: () => void; } diff --git a/src/plugins/embeddable/public/embeddable_panel/panel_header/embeddable_panel_context_menu.tsx b/src/plugins/embeddable/public/embeddable_panel/panel_header/embeddable_panel_context_menu.tsx index 5fe6461083cc5..e3f4b1e7af580 100644 --- a/src/plugins/embeddable/public/embeddable_panel/panel_header/embeddable_panel_context_menu.tsx +++ b/src/plugins/embeddable/public/embeddable_panel/panel_header/embeddable_panel_context_menu.tsx @@ -25,7 +25,7 @@ import { uiActions } from '../../kibana_services'; import { EmbeddablePanelProps, PanelUniversalActions } from '../types'; import { getContextMenuAriaLabel } from '../embeddable_panel_strings'; import { useSelectFromEmbeddableInput } from '../use_select_from_embeddable'; -import { IEmbeddable, contextMenuTrigger, CONTEXT_MENU_TRIGGER, ViewMode } from '../..'; +import { IEmbeddable, contextMenuTrigger, CONTEXT_MENU_TRIGGER } from '../..'; const sortByOrderField = ( { order: orderA }: { order?: number }, @@ -56,7 +56,6 @@ export const EmbeddablePanelContextMenu = ({ const [contextMenuPanels, setContextMenuPanels] = useState([]); const title = useSelectFromEmbeddableInput('title', embeddable); - const viewMode = useSelectFromEmbeddableInput('viewMode', embeddable); useEffect(() => { /** @@ -135,7 +134,7 @@ export const EmbeddablePanelContextMenu = ({ data-test-subj="embeddablePanelToggleMenuIcon" aria-label={getContextMenuAriaLabel(title, index)} onClick={() => setIsContextMenuOpen((isOpen) => !isOpen)} - iconType={viewMode === ViewMode.VIEW ? 'boxesHorizontal' : 'gear'} + iconType={'boxesHorizontal'} /> ); diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/helpers.ts b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/helpers.ts index 1decd82c4ed19..80156ae1442aa 100644 --- a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/helpers.ts +++ b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/helpers.ts @@ -6,8 +6,8 @@ */ import React from 'react'; import './helpers.scss'; -import type { IEmbeddable } from '@kbn/embeddable-plugin/public'; -import type { OverlayRef, OverlayStart, ThemeServiceStart } from '@kbn/core/public'; +import { IEmbeddable, tracksOverlays } from '@kbn/embeddable-plugin/public'; +import type { OverlayStart, ThemeServiceStart } from '@kbn/core/public'; import { toMountPoint } from '@kbn/kibana-react-plugin/public'; import { IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; import { isLensEmbeddable } from '../utils'; @@ -20,15 +20,6 @@ interface Context { theme: ThemeServiceStart; } -interface TracksOverlays { - openOverlay: (ref: OverlayRef) => void; - clearOverlays: () => void; -} - -function tracksOverlays(root: unknown): root is TracksOverlays { - return Boolean((root as TracksOverlays).openOverlay && (root as TracksOverlays).clearOverlays); -} - export async function isActionCompatible(embeddable: IEmbeddable) { return Boolean(isLensEmbeddable(embeddable) && embeddable.isTextBasedLanguage()); } @@ -67,6 +58,6 @@ export async function executeAction({ embeddable, startDependencies, overlays, t outsideClickCloses: true, } ); - overlayTracker?.openOverlay(handle); + overlayTracker?.openOverlay(handle, { focusedPanelId: embeddable.id }); } } From 46629609806b424533c4a7ae148f7292890f849d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Tue, 26 Sep 2023 01:06:35 +0200 Subject: [PATCH 38/45] [APM] Add permissions for "input-only" package (#166234) Closes: https://github.com/elastic/kibana/issues/164936 This grants the necessary permissions to APM Server when running under fleet. --- .../fleet/common/types/models/agent_policy.ts | 12 +- .../cloud_preconfiguration.test.ts | 28 +- ...kage_policies_to_agent_permissions.test.ts | 100 ++++++- .../package_policies_to_agent_permissions.ts | 250 ++++++++++-------- .../apm_api_integration/common/bettertest.ts | 20 +- .../tests/fleet/apm_package_policy.spec.ts | 17 +- ...apm_package_policy_setup.ts => helpers.ts} | 65 ++++- .../tests/fleet/input_only_package.spec.ts | 236 +++++++++++++++++ .../tests/fleet/migration_check.spec.ts | 20 +- 9 files changed, 566 insertions(+), 182 deletions(-) rename x-pack/test/apm_api_integration/tests/fleet/{apm_package_policy_setup.ts => helpers.ts} (63%) create mode 100644 x-pack/test/apm_api_integration/tests/fleet/input_only_package.spec.ts diff --git a/x-pack/plugins/fleet/common/types/models/agent_policy.ts b/x-pack/plugins/fleet/common/types/models/agent_policy.ts index 919d67392770d..a653bbfb8b223 100644 --- a/x-pack/plugins/fleet/common/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/common/types/models/agent_policy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import type { SecurityRoleDescriptor } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + import type { agentPolicyStatuses } from '../../constants'; import type { MonitoringType, PolicySecretReference, ValueOf } from '..'; @@ -77,15 +79,7 @@ export interface FullAgentPolicyInput { [key: string]: any; } -export interface FullAgentPolicyOutputPermissions { - [packagePolicyName: string]: { - cluster?: string[]; - indices?: Array<{ - names: string[]; - privileges: string[]; - }>; - }; -} +export type FullAgentPolicyOutputPermissions = Record; export type FullAgentPolicyOutput = Pick & { proxy_url?: string; diff --git a/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts b/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts index c6eaba98135f3..139f07fb999b3 100644 --- a/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts +++ b/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts @@ -312,31 +312,11 @@ describe('Fleet preconfiguration reset', () => { cluster: ['cluster:monitor/main'], indices: [ { - names: ['logs-apm.app-default'], + names: ['traces-*', 'logs-*', 'metrics-*'], privileges: ['auto_configure', 'create_doc'], }, { - names: ['metrics-apm.app.*-default'], - privileges: ['auto_configure', 'create_doc'], - }, - { - names: ['logs-apm.error-default'], - privileges: ['auto_configure', 'create_doc'], - }, - { - names: ['metrics-apm.internal-default'], - privileges: ['auto_configure', 'create_doc'], - }, - { - names: ['metrics-apm.profiling-default'], - privileges: ['auto_configure', 'create_doc'], - }, - { - names: ['traces-apm.rum-default'], - privileges: ['auto_configure', 'create_doc'], - }, - { - names: ['traces-apm.sampled-default'], + names: ['traces-apm.sampled-*'], privileges: [ 'auto_configure', 'create_doc', @@ -345,10 +325,6 @@ describe('Fleet preconfiguration reset', () => { 'read', ], }, - { - names: ['traces-apm-default'], - privileges: ['auto_configure', 'create_doc'], - }, ], }, }, diff --git a/x-pack/plugins/fleet/server/services/agent_policies/package_policies_to_agent_permissions.test.ts b/x-pack/plugins/fleet/server/services/agent_policies/package_policies_to_agent_permissions.test.ts index 8bd45d80d9429..e4f2b30bc4a9e 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/package_policies_to_agent_permissions.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/package_policies_to_agent_permissions.test.ts @@ -239,26 +239,66 @@ packageInfoCache.set('profiler_collector-8.9.0-preview', { }, }); +packageInfoCache.set('apm-8.9.0-preview', { + format_version: '2.7.0', + name: 'apm', + title: 'APM', + version: '8.9.0-preview', + license: 'basic', + description: 'APM Server integration', + type: 'integration', + release: 'beta', + categories: ['observability'], + icons: [], + owner: { github: 'elastic/apm-server' }, + data_streams: [], + latestVersion: '8.9.0-preview', + status: 'not_installed', + assets: { + kibana: { + csp_rule_template: [], + dashboard: [], + visualization: [], + search: [], + index_pattern: [], + map: [], + lens: [], + security_rule: [], + ml_module: [], + tag: [], + osquery_pack_asset: [], + osquery_saved_query: [], + }, + elasticsearch: { + component_template: [], + ingest_pipeline: [], + ilm_policy: [], + transform: [], + index_template: [], + data_stream_ilm_policy: [], + ml_model: [], + }, + }, +}); + describe('storedPackagePoliciesToAgentPermissions()', () => { it('Returns `undefined` if there are no package policies', async () => { const permissions = await storedPackagePoliciesToAgentPermissions(packageInfoCache, []); expect(permissions).toBeUndefined(); }); - it('Throw an error if package policies is not an array', async () => { - await expect(() => - storedPackagePoliciesToAgentPermissions(packageInfoCache, undefined) - ).rejects.toThrow( + it('Throw an error if package policies is not an array', () => { + expect(() => storedPackagePoliciesToAgentPermissions(packageInfoCache, undefined)).toThrow( /storedPackagePoliciesToAgentPermissions should be called with a PackagePolicy/ ); }); - it('Returns the default permissions if a package policy does not have a package', async () => { - await expect(() => + it('Returns the default permissions if a package policy does not have a package', () => { + expect(() => storedPackagePoliciesToAgentPermissions(packageInfoCache, [ { name: 'foo', package: undefined } as PackagePolicy, ]) - ).rejects.toThrow(/No package for package policy foo/); + ).toThrow(/No package for package policy foo/); }); it('Returns the permissions for the enabled inputs', async () => { @@ -545,6 +585,52 @@ describe('storedPackagePoliciesToAgentPermissions()', () => { }, }); }); + + it('returns the correct permissions for the APM package', async () => { + const packagePolicies: PackagePolicy[] = [ + { + id: 'package-policy-uuid-test-123', + name: 'test-policy', + namespace: '', + enabled: true, + package: { name: 'apm', version: '8.9.0-preview', title: 'Test Package' }, + inputs: [ + { + type: 'pf-elastic-collector', + enabled: true, + streams: [], + }, + ], + created_at: '', + updated_at: '', + created_by: '', + updated_by: '', + revision: 1, + policy_id: '', + }, + ]; + + const permissions = await storedPackagePoliciesToAgentPermissions( + packageInfoCache, + packagePolicies + ); + + expect(permissions).toMatchObject({ + 'package-policy-uuid-test-123': { + cluster: ['cluster:monitor/main'], + indices: [ + { + names: ['traces-*', 'logs-*', 'metrics-*'], + privileges: ['auto_configure', 'create_doc'], + }, + { + names: ['traces-apm.sampled-*'], + privileges: ['auto_configure', 'create_doc', 'maintenance', 'monitor', 'read'], + }, + ], + }, + }); + }); }); describe('getDataStreamPrivileges()', () => { diff --git a/x-pack/plugins/fleet/server/services/agent_policies/package_policies_to_agent_permissions.ts b/x-pack/plugins/fleet/server/services/agent_policies/package_policies_to_agent_permissions.ts index eeb81ca9c1724..4445ebbe84769 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/package_policies_to_agent_permissions.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/package_policies_to_agent_permissions.ts @@ -5,7 +5,13 @@ * 2.0. */ +import type { + SecurityIndicesPrivileges, + SecurityRoleDescriptor, +} from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + import { + FLEET_APM_PACKAGE, FLEET_UNIVERSAL_PROFILING_COLLECTOR_PACKAGE, FLEET_UNIVERSAL_PROFILING_SYMBOLIZER_PACKAGE, } from '../../../common/constants'; @@ -34,10 +40,10 @@ export const UNIVERSAL_PROFILING_PERMISSIONS = [ 'view_index_metadata', ]; -export async function storedPackagePoliciesToAgentPermissions( +export function storedPackagePoliciesToAgentPermissions( packageInfoCache: Map, packagePolicies?: PackagePolicy[] -): Promise { +): FullAgentPolicyOutputPermissions | undefined { // I'm not sure what permissions to return for this case, so let's return the defaults if (!packagePolicies) { throw new Error( @@ -49,114 +55,116 @@ export async function storedPackagePoliciesToAgentPermissions( return; } - const permissionEntries = (packagePolicies as PackagePolicy[]).map>( - async (packagePolicy) => { - if (!packagePolicy.package) { - throw new Error(`No package for package policy ${packagePolicy.name ?? packagePolicy.id}`); - } - - const pkg = packageInfoCache.get(pkgToPkgKey(packagePolicy.package))!; - - // Special handling for Universal Profiling packages, as it does not use data streams _only_, - // but also indices that do not adhere to the convention. - if ( - pkg.name === FLEET_UNIVERSAL_PROFILING_SYMBOLIZER_PACKAGE || - pkg.name === FLEET_UNIVERSAL_PROFILING_COLLECTOR_PACKAGE - ) { - return Promise.resolve(universalProfilingPermissions(packagePolicy.id)); - } - - const dataStreams = getNormalizedDataStreams(pkg); - if (!dataStreams || dataStreams.length === 0) { - return [packagePolicy.name, undefined]; - } - - let dataStreamsForPermissions: DataStreamMeta[]; - - switch (pkg.name) { - case 'endpoint': - // - Endpoint doesn't store the `data_stream` metadata in - // `packagePolicy.inputs`, so we will use _all_ data_streams from the - // package. - dataStreamsForPermissions = dataStreams; - break; - - case 'apm': - // - APM doesn't store the `data_stream` metadata in - // `packagePolicy.inputs`, so we will use _all_ data_streams from - // the package. - dataStreamsForPermissions = dataStreams; - break; - - case 'osquery_manager': - // - Osquery manager doesn't store the `data_stream` metadata in - // `packagePolicy.inputs`, so we will use _all_ data_streams from - // the package. - dataStreamsForPermissions = dataStreams; - break; - - default: - // - Normal packages store some of the `data_stream` metadata in - // `packagePolicy.inputs[].streams[].data_stream` - // - The rest of the metadata needs to be fetched from the - // `data_stream` object in the package. The link is - // `packagePolicy.inputs[].type == dataStreams.streams[].input` - // - Some packages (custom logs) have a compiled dataset, stored in - // `input.streams.compiled_stream.data_stream.dataset` - dataStreamsForPermissions = packagePolicy.inputs - .filter((i) => i.enabled) - .flatMap((input) => { - if (!input.streams) { - return []; - } - - const dataStreams_: DataStreamMeta[] = []; - - input.streams - .filter((s) => s.enabled) - .forEach((stream) => { - if (!('data_stream' in stream)) { - return; - } - - const ds: DataStreamMeta = { - type: stream.data_stream.type, - dataset: - stream.compiled_stream?.data_stream?.dataset ?? stream.data_stream.dataset, - }; - - if (stream.data_stream.elasticsearch) { - ds.elasticsearch = stream.data_stream.elasticsearch; - } - - dataStreams_.push(ds); - }); - - return dataStreams_; - }); - } - - let clusterRoleDescriptor = {}; - const cluster = packagePolicy?.elasticsearch?.privileges?.cluster ?? []; - if (cluster.length > 0) { - clusterRoleDescriptor = { - cluster, - }; - } - - return [ - packagePolicy.id, - { - indices: dataStreamsForPermissions.map((ds) => - getDataStreamPrivileges(ds, packagePolicy.namespace) - ), - ...clusterRoleDescriptor, - }, - ]; + const permissionEntries = packagePolicies.map((packagePolicy) => { + if (!packagePolicy.package) { + throw new Error(`No package for package policy ${packagePolicy.name ?? packagePolicy.id}`); + } + + const pkg = packageInfoCache.get(pkgToPkgKey(packagePolicy.package))!; + + // Special handling for Universal Profiling packages, as it does not use data streams _only_, + // but also indices that do not adhere to the convention. + if ( + pkg.name === FLEET_UNIVERSAL_PROFILING_SYMBOLIZER_PACKAGE || + pkg.name === FLEET_UNIVERSAL_PROFILING_COLLECTOR_PACKAGE + ) { + return universalProfilingPermissions(packagePolicy.id); + } + + if (pkg.name === FLEET_APM_PACKAGE) { + return apmPermissions(packagePolicy.id); + } + + const dataStreams = getNormalizedDataStreams(pkg); + if (!dataStreams || dataStreams.length === 0) { + return [packagePolicy.name, undefined]; + } + + let dataStreamsForPermissions: DataStreamMeta[]; + + switch (pkg.name) { + case 'endpoint': + // - Endpoint doesn't store the `data_stream` metadata in + // `packagePolicy.inputs`, so we will use _all_ data_streams from the + // package. + dataStreamsForPermissions = dataStreams; + break; + + case 'apm': + // - APM doesn't store the `data_stream` metadata in + // `packagePolicy.inputs`, so we will use _all_ data_streams from + // the package. + dataStreamsForPermissions = dataStreams; + break; + + case 'osquery_manager': + // - Osquery manager doesn't store the `data_stream` metadata in + // `packagePolicy.inputs`, so we will use _all_ data_streams from + // the package. + dataStreamsForPermissions = dataStreams; + break; + + default: + // - Normal packages store some of the `data_stream` metadata in + // `packagePolicy.inputs[].streams[].data_stream` + // - The rest of the metadata needs to be fetched from the + // `data_stream` object in the package. The link is + // `packagePolicy.inputs[].type == dataStreams.streams[].input` + // - Some packages (custom logs) have a compiled dataset, stored in + // `input.streams.compiled_stream.data_stream.dataset` + dataStreamsForPermissions = packagePolicy.inputs + .filter((i) => i.enabled) + .flatMap((input) => { + if (!input.streams) { + return []; + } + + const dataStreams_: DataStreamMeta[] = []; + + input.streams + .filter((s) => s.enabled) + .forEach((stream) => { + if (!('data_stream' in stream)) { + return; + } + + const ds: DataStreamMeta = { + type: stream.data_stream.type, + dataset: + stream.compiled_stream?.data_stream?.dataset ?? stream.data_stream.dataset, + }; + + if (stream.data_stream.elasticsearch) { + ds.elasticsearch = stream.data_stream.elasticsearch; + } + + dataStreams_.push(ds); + }); + + return dataStreams_; + }); + } + + let clusterRoleDescriptor = {}; + const cluster = packagePolicy?.elasticsearch?.privileges?.cluster ?? []; + if (cluster.length > 0) { + clusterRoleDescriptor = { + cluster, + }; } - ); - return Object.fromEntries(await Promise.all(permissionEntries)); + return [ + packagePolicy.id, + { + indices: dataStreamsForPermissions.map((ds) => + getDataStreamPrivileges(ds, packagePolicy.namespace) + ), + ...clusterRoleDescriptor, + }, + ]; + }); + + return Object.fromEntries(permissionEntries); } export interface DataStreamMeta { @@ -171,7 +179,10 @@ export interface DataStreamMeta { }; } -export function getDataStreamPrivileges(dataStream: DataStreamMeta, namespace: string = '*') { +export function getDataStreamPrivileges( + dataStream: DataStreamMeta, + namespace: string = '*' +): SecurityIndicesPrivileges { let index = dataStream.hidden ? `.${dataStream.type}-` : `${dataStream.type}-`; // Determine dataset @@ -200,7 +211,7 @@ export function getDataStreamPrivileges(dataStream: DataStreamMeta, namespace: s }; } -async function universalProfilingPermissions(packagePolicyId: string): Promise<[string, any]> { +function universalProfilingPermissions(packagePolicyId: string): [string, SecurityRoleDescriptor] { const profilingIndexPattern = 'profiling-*'; return [ packagePolicyId, @@ -214,3 +225,22 @@ async function universalProfilingPermissions(packagePolicyId: string): Promise<[ }, ]; } + +function apmPermissions(packagePolicyId: string): [string, SecurityRoleDescriptor] { + return [ + packagePolicyId, + { + cluster: ['cluster:monitor/main'], + indices: [ + { + names: ['traces-*', 'logs-*', 'metrics-*'], + privileges: ['auto_configure', 'create_doc'], + }, + { + names: ['traces-apm.sampled-*'], + privileges: ['auto_configure', 'create_doc', 'maintenance', 'monitor', 'read'], + }, + ], + }, + ]; +} diff --git a/x-pack/test/apm_api_integration/common/bettertest.ts b/x-pack/test/apm_api_integration/common/bettertest.ts index 41580983917a3..83f7da5725db8 100644 --- a/x-pack/test/apm_api_integration/common/bettertest.ts +++ b/x-pack/test/apm_api_integration/common/bettertest.ts @@ -11,20 +11,32 @@ import request from 'superagent'; type HttpMethod = 'get' | 'post' | 'put' | 'delete'; -export type BetterTest = (options: { +export type BetterTest = (options: BetterTestOptions) => Promise>; + +interface BetterTestOptions { pathname: string; query?: Record; method?: HttpMethod; body?: any; -}) => Promise<{ status: number; body: T }>; +} + +interface BetterTestResponse { + status: number; + body: T; +} /* * This is a wrapper around supertest that throws an error if the response status is not 200. * This is useful for tests that expect a 200 response * It also makes it easier to debug tests that fail because of a 500 response. */ -export function getBettertest(st: supertest.SuperTest): BetterTest { - return async ({ pathname, method = 'get', query, body }) => { +export function getBettertest(st: supertest.SuperTest) { + return async ({ + pathname, + method = 'get', + query, + body, + }: BetterTestOptions): Promise> => { const url = format({ pathname, query }); let res: request.Response; diff --git a/x-pack/test/apm_api_integration/tests/fleet/apm_package_policy.spec.ts b/x-pack/test/apm_api_integration/tests/fleet/apm_package_policy.spec.ts index 0ba4336b36e0c..d78a6fa6d99d6 100644 --- a/x-pack/test/apm_api_integration/tests/fleet/apm_package_policy.spec.ts +++ b/x-pack/test/apm_api_integration/tests/fleet/apm_package_policy.spec.ts @@ -5,7 +5,6 @@ * 2.0. */ -import * as Url from 'url'; import { PackagePolicy } from '@kbn/fleet-plugin/common'; import { AGENT_CONFIG_PATH, @@ -17,7 +16,7 @@ import expect from '@kbn/expect'; import { get } from 'lodash'; import type { SourceMap } from '@kbn/apm-plugin/server/routes/source_maps/route'; import { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; -import { createEsClientForTesting } from '@kbn/test'; +import { createEsClientForFtrConfig } from '@kbn/test'; import { APM_AGENT_CONFIGURATION_INDEX, APM_SOURCE_MAP_INDEX, @@ -30,7 +29,7 @@ import { deletePackagePolicy, getPackagePolicy, setupFleet, -} from './apm_package_policy_setup'; +} from './helpers'; import { getBettertest } from '../../common/bettertest'; import { expectToReject } from '../../common/utils/expect_to_reject'; @@ -41,14 +40,10 @@ export default function ApiTest(ftrProviderContext: FtrProviderContext) { const supertest = getService('supertest'); const es = getService('es'); const bettertest = getBettertest(supertest); + const configService = getService('config'); function createEsClientWithApiKeyAuth({ id, apiKey }: { id: string; apiKey: string }) { - const config = getService('config'); - return createEsClientForTesting({ - esUrl: Url.format(config.get('servers.elasticsearch')), - requestTimeout: config.get('timeouts.esRequestTimeout'), - auth: { apiKey: { id, api_key: apiKey } }, - }); + return createEsClientForFtrConfig(configService, { auth: { apiKey: { id, api_key: apiKey } } }); } async function createConfiguration(configuration: any) { @@ -120,8 +115,8 @@ export default function ApiTest(ftrProviderContext: FtrProviderContext) { before(async () => { await setupFleet(bettertest); - agentPolicyId = await createAgentPolicy(bettertest); - packagePolicyId = await createPackagePolicy(bettertest, agentPolicyId); + agentPolicyId = await createAgentPolicy({ bettertest }); + packagePolicyId = await createPackagePolicy({ bettertest, agentPolicyId }); apmPackagePolicy = await getPackagePolicy(bettertest, packagePolicyId); // make sure to get the latest package policy }); diff --git a/x-pack/test/apm_api_integration/tests/fleet/apm_package_policy_setup.ts b/x-pack/test/apm_api_integration/tests/fleet/helpers.ts similarity index 63% rename from x-pack/test/apm_api_integration/tests/fleet/apm_package_policy_setup.ts rename to x-pack/test/apm_api_integration/tests/fleet/helpers.ts index aeb2f00fb9360..9cedf76b221b1 100644 --- a/x-pack/test/apm_api_integration/tests/fleet/apm_package_policy_setup.ts +++ b/x-pack/test/apm_api_integration/tests/fleet/helpers.ts @@ -11,15 +11,23 @@ export function setupFleet(bettertest: BetterTest) { return bettertest({ pathname: '/api/fleet/setup', method: 'post' }); } -export async function createAgentPolicy(bettertest: BetterTest, id?: string) { +export async function createAgentPolicy({ + bettertest, + id, + name = 'test_agent_policy', +}: { + bettertest: BetterTest; + id?: string; + name?: string; +}) { const agentPolicyResponse = await bettertest<{ item: AgentPolicy }>({ pathname: '/api/fleet/agent_policies', method: 'post', query: { sys_monitoring: true }, body: { - name: 'test_agent_policy', - description: '', id, + name, + description: '', namespace: 'default', monitoring_enabled: ['logs', 'metrics'], }, @@ -28,11 +36,17 @@ export async function createAgentPolicy(bettertest: BetterTest, id?: string) { return agentPolicyResponse.body.item.id; } -export async function createPackagePolicy( - bettertest: BetterTest, - agentPolicyId: string, - id?: string -) { +export async function createPackagePolicy({ + bettertest, + agentPolicyId, + id, + name = 'apm-integration-test-policy', +}: { + bettertest: BetterTest; + agentPolicyId: string; + id?: string; + name?: string; +}) { // Get version of available APM package const apmPackageResponse = await bettertest<{ item: any }>({ pathname: `/api/fleet/epm/packages/apm`, @@ -44,7 +58,7 @@ export async function createPackagePolicy( pathname: '/api/fleet/package_policies', method: 'post', body: { - name: 'apm-integration-test-policy', + name, description: '', namespace: 'default', policy_id: agentPolicyId, @@ -82,3 +96,36 @@ export async function getPackagePolicy( }); return res.body.item; } + +async function getAgentPolicyByName(bettertest: BetterTest, name: string): Promise { + const res = await bettertest<{ items: PackagePolicy[] }>({ + pathname: `/api/fleet/agent_policies`, + query: { + full: true, + kuery: `name:"${name}"`, + }, + }); + return res.body.items[0]; +} + +export async function deleteAgentPolicyAndPackagePolicyByName({ + bettertest, + agentPolicyName, + packagePolicyName, +}: { + bettertest: BetterTest; + agentPolicyName: string; + packagePolicyName: string; +}) { + const agentPolicy = await getAgentPolicyByName(bettertest, agentPolicyName); + + const agentPolicyId = agentPolicy.id; + // @ts-expect-error + const packagePolicies = agentPolicy.package_policies as PackagePolicy[]; + const packagePolicyId = packagePolicies.find( + (packagePolicy) => packagePolicy.name === packagePolicyName + )!.id; + + await deleteAgentPolicy(bettertest, agentPolicyId); + await deletePackagePolicy(bettertest, packagePolicyId); +} diff --git a/x-pack/test/apm_api_integration/tests/fleet/input_only_package.spec.ts b/x-pack/test/apm_api_integration/tests/fleet/input_only_package.spec.ts new file mode 100644 index 0000000000000..982d37b802792 --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/fleet/input_only_package.spec.ts @@ -0,0 +1,236 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { apm, timerange } from '@kbn/apm-synthtrace-client'; +import { ApmSynthtraceEsClient, createLogger, LogLevel } from '@kbn/apm-synthtrace'; +import expect from '@kbn/expect'; +import { createEsClientForFtrConfig } from '@kbn/test'; +import { ApmDocumentType } from '@kbn/apm-plugin/common/document_type'; +import { RollupInterval } from '@kbn/apm-plugin/common/rollup'; +import { SecurityRoleDescriptor } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import pRetry from 'p-retry'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { getBettertest } from '../../common/bettertest'; +import { + createAgentPolicy, + createPackagePolicy, + deleteAgentPolicyAndPackagePolicyByName, + setupFleet, +} from './helpers'; +import { ApmApiClient } from '../../common/config'; + +export default function ApiTest(ftrProviderContext: FtrProviderContext) { + const { getService } = ftrProviderContext; + const registry = getService('registry'); + const apmApiClient = getService('apmApiClient'); + const supertest = getService('supertest'); + const es = getService('es'); + const log = getService('log'); + const bettertest = getBettertest(supertest); + const config = getService('config'); + const synthtraceKibanaClient = getService('synthtraceKibanaClient'); + const synthtraceEsClient = getService('synthtraceEsClient'); + + const API_KEY_NAME = 'apm_api_key_testing'; + const APM_AGENT_POLICY_NAME = 'apm_agent_policy_testing'; + const APM_PACKAGE_POLICY_NAME = 'apm_package_policy_testing'; + + function createEsClientWithApiKey({ id, apiKey }: { id: string; apiKey: string }) { + return createEsClientForFtrConfig(config, { auth: { apiKey: { id, api_key: apiKey } } }); + } + + function createEsClientWithToken(token: string) { + return createEsClientForFtrConfig(config, { auth: { bearer: token } }); + } + + async function getApiKeyForServiceAccount( + serviceAccount: string, + permissions: SecurityRoleDescriptor + ) { + const { token } = await es.security.createServiceToken({ + namespace: 'elastic', + service: serviceAccount, + }); + + const esClientScoped = createEsClientWithToken(token.value); + return esClientScoped.security.createApiKey({ + body: { + name: API_KEY_NAME, + role_descriptors: { + apmFleetPermissions: permissions, + }, + }, + }); + } + + async function getSynthtraceClientWithApiKey({ + id, + api_key: apiKey, + }: { + id: string; + api_key: string; + }) { + const esClient = createEsClientWithApiKey({ id, apiKey }); + const kibanaVersion = await synthtraceKibanaClient.fetchLatestApmPackageVersion(); + return new ApmSynthtraceEsClient({ + client: esClient, + logger: createLogger(LogLevel.info), + version: kibanaVersion, + refreshAfterIndex: true, + }); + } + + registry.when('APM package policy', { config: 'basic', archives: [] }, () => { + async function getAgentPolicyPermissions(agentPolicyId: string, packagePolicyId: string) { + const res = await bettertest<{ + item: { output_permissions: { default: Record } }; + }>({ + pathname: `/api/fleet/agent_policies/${agentPolicyId}/full`, + method: 'get', + }); + + return res.body.item.output_permissions.default[packagePolicyId]; + } + + describe('input only package', () => { + let agentPolicyId: string; + let packagePolicyId: string; + let permissions: SecurityRoleDescriptor; + + async function cleanAll() { + try { + await synthtraceEsClient.clean(); + await es.security.invalidateApiKey({ name: API_KEY_NAME }); + await deleteAgentPolicyAndPackagePolicyByName({ + bettertest, + agentPolicyName: APM_AGENT_POLICY_NAME, + packagePolicyName: APM_PACKAGE_POLICY_NAME, + }); + } catch (e) { + log.info('Nothing to clean'); + } + } + + before(async () => { + await cleanAll(); + + await setupFleet(bettertest); + agentPolicyId = await createAgentPolicy({ bettertest, name: APM_AGENT_POLICY_NAME }); + packagePolicyId = await createPackagePolicy({ + bettertest, + agentPolicyId, + name: APM_PACKAGE_POLICY_NAME, + }); + + permissions = await getAgentPolicyPermissions(agentPolicyId, packagePolicyId); + }); + + after(async () => { + await cleanAll(); + }); + + it('has permissions in the agent policy', async () => { + expect(permissions).to.eql({ + cluster: ['cluster:monitor/main'], + indices: [ + { + names: ['traces-*', 'logs-*', 'metrics-*'], + privileges: ['auto_configure', 'create_doc'], + }, + { + names: ['traces-apm.sampled-*'], + privileges: ['auto_configure', 'create_doc', 'maintenance', 'monitor', 'read'], + }, + ], + }); + }); + + describe('when ingesting events using the scoped api key', () => { + let scenario: ReturnType; + + before(async () => { + scenario = getSynthtraceScenario(); + + // get api key scoped to the specified permissions and created with the fleet-server service account. This ensures that the api key is not created with more permissions than fleet-server is able to. + const apiKey = await getApiKeyForServiceAccount('fleet-server', permissions); + + // create a synthtrace client scoped to the api key. This verifies that the api key has permissions to write to the APM indices. + const scopedSynthtraceEsClient = await getSynthtraceClientWithApiKey(apiKey); + await scopedSynthtraceEsClient.index(scenario.events); + }); + + it('the events can be seen on the Service Inventory Page', async () => { + const apmServices = await getApmServices(apmApiClient, scenario.start, scenario.end); + expect(apmServices[0].serviceName).to.be('opbeans-java'); + expect(apmServices[0].environments?.[0]).to.be('ingested-via-fleet'); + expect(apmServices[0].latency).to.be(2550000); + expect(apmServices[0].throughput).to.be(2); + expect(apmServices[0].transactionErrorRate).to.be(0.5); + }); + }); + }); + }); +} + +function getApmServices(apmApiClient: ApmApiClient, start: string, end: string) { + return pRetry(async () => { + const res = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/services', + params: { + query: { + start, + end, + probability: 1, + environment: 'ENVIRONMENT_ALL', + kuery: '', + documentType: ApmDocumentType.TransactionMetric, + rollupInterval: RollupInterval.OneMinute, + }, + }, + }); + + if (res.body.items.length === 0 || !res.body.items[0].latency) { + throw new Error(`Timed-out: No APM Services were found`); + } + + return res.body.items; + }); +} + +function getSynthtraceScenario() { + const start = new Date('2023-09-01T00:00:00.000Z').getTime(); + const end = new Date('2023-09-01T00:02:00.000Z').getTime(); + + const opbeansJava = apm + .service({ name: 'opbeans-java', environment: 'ingested-via-fleet', agentName: 'java' }) + .instance('instance'); + + const events = timerange(start, end) + .ratePerMinute(1) + .generator((timestamp) => { + return [ + opbeansJava + .transaction({ transactionName: 'tx-java' }) + .timestamp(timestamp) + .duration(5000) + .success(), + + opbeansJava + .transaction({ transactionName: 'tx-java' }) + .timestamp(timestamp) + .duration(100) + .failure() + .errors(opbeansJava.error({ message: 'some error' }).timestamp(timestamp + 50)), + ]; + }); + + return { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + events, + }; +} diff --git a/x-pack/test/apm_api_integration/tests/fleet/migration_check.spec.ts b/x-pack/test/apm_api_integration/tests/fleet/migration_check.spec.ts index 1f89f65c536b9..74cf37c957d13 100644 --- a/x-pack/test/apm_api_integration/tests/fleet/migration_check.spec.ts +++ b/x-pack/test/apm_api_integration/tests/fleet/migration_check.spec.ts @@ -13,7 +13,7 @@ import { deleteAgentPolicy, deletePackagePolicy, setupFleet, -} from './apm_package_policy_setup'; +} from './helpers'; import { getBettertest } from '../../common/bettertest'; export default function ApiTest(ftrProviderContext: FtrProviderContext) { @@ -76,7 +76,7 @@ export default function ApiTest(ftrProviderContext: FtrProviderContext) { }); describe('with Cloud agent policy', () => { before(async () => { - await createAgentPolicy(bettertest, 'policy-elastic-agent-on-cloud'); + await createAgentPolicy({ bettertest, id: 'policy-elastic-agent-on-cloud' }); }); after(async () => { await deleteAgentPolicy(bettertest, 'policy-elastic-agent-on-cloud'); @@ -92,7 +92,7 @@ export default function ApiTest(ftrProviderContext: FtrProviderContext) { describe('has_cloud_apm_package_policy', () => { before(async () => { - await createAgentPolicy(bettertest, 'policy-elastic-agent-on-cloud'); + await createAgentPolicy({ bettertest, id: 'policy-elastic-agent-on-cloud' }); }); after(async () => { await deleteAgentPolicy(bettertest, 'policy-elastic-agent-on-cloud'); @@ -107,7 +107,11 @@ export default function ApiTest(ftrProviderContext: FtrProviderContext) { }); describe('with Cloud APM package policy', () => { before(async () => { - await createPackagePolicy(bettertest, 'policy-elastic-agent-on-cloud', 'apm'); + await createPackagePolicy({ + bettertest, + agentPolicyId: 'policy-elastic-agent-on-cloud', + id: 'apm', + }); }); after(async () => { await deletePackagePolicy(bettertest, 'apm'); @@ -125,7 +129,7 @@ export default function ApiTest(ftrProviderContext: FtrProviderContext) { describe('has_apm_integrations', () => { before(async () => { - await createAgentPolicy(bettertest, 'test-agent-policy'); + await createAgentPolicy({ bettertest, id: 'test-agent-policy' }); }); after(async () => { await deleteAgentPolicy(bettertest, 'test-agent-policy'); @@ -139,7 +143,11 @@ export default function ApiTest(ftrProviderContext: FtrProviderContext) { }); describe('with custom APM package policy', () => { before(async () => { - await createPackagePolicy(bettertest, 'test-agent-policy', 'test-apm-package-policy'); + await createPackagePolicy({ + bettertest, + agentPolicyId: 'test-agent-policy', + id: 'test-apm-package-policy', + }); }); after(async () => { await deletePackagePolicy(bettertest, 'test-apm-package-policy'); From e81728ee9672400d35da4122ca683541c1b7753d Mon Sep 17 00:00:00 2001 From: Alex Szabo Date: Tue, 26 Sep 2023 01:28:56 +0200 Subject: [PATCH 39/45] Fix typecheck foundations (#167060) ## Summary This PR is the core part of #166813. The original work seems to grow large, and we'd like to enable a preventive check beforehand to prevent more errors from entering the codebase. The idea is to have a selective type check that would only check changed files' projects. - [x] when there's no extra label, run the selective type check only on the diffing files' projects (success: https://buildkite.com/elastic/kibana-pull-request/builds/161837) - [x] when the label `ci:hard-typecheck` is present, run the regular (but now, working) full typecheck (expected to fail: ) cc: @watson --------- Co-authored-by: Brad White Co-authored-by: Thomas Watson Co-authored-by: Thomas Watson Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .buildkite/pipelines/pull_request/base.yml | 19 +-- .../pipelines/pull_request/type_check.yml | 10 ++ .../pull_request/type_check_selective.yml | 10 ++ .../pipelines/pull_request/pipeline.ts | 6 + .buildkite/scripts/steps/build_api_docs.sh | 5 +- .../scripts/steps/check_types_commits.sh | 114 ++++++++++++++++++ package.json | 3 +- packages/kbn-dev-proc-runner/src/proc.ts | 24 +++- .../kbn-dev-proc-runner/src/proc_runner.ts | 3 + .../run_type_check_cli.ts | 3 + 10 files changed, 181 insertions(+), 16 deletions(-) create mode 100644 .buildkite/pipelines/pull_request/type_check.yml create mode 100644 .buildkite/pipelines/pull_request/type_check_selective.yml create mode 100644 .buildkite/scripts/steps/check_types_commits.sh diff --git a/.buildkite/pipelines/pull_request/base.yml b/.buildkite/pipelines/pull_request/base.yml index 158c22c0bb0c5..9c2527fcdd413 100644 --- a/.buildkite/pipelines/pull_request/base.yml +++ b/.buildkite/pipelines/pull_request/base.yml @@ -136,12 +136,13 @@ steps: - exit_status: '-1' limit: 3 - - command: .buildkite/scripts/steps/check_types.sh - label: 'Check Types' - agents: - queue: n2-16-spot - timeout_in_minutes: 60 - retry: - automatic: - - exit_status: '-1' - limit: 3 +# TODO: Enable in #166813 after fixing types +# - command: .buildkite/scripts/steps/check_types.sh +# label: 'Check Types' +# agents: +# queue: n2-16-spot +# timeout_in_minutes: 60 +# retry: +# automatic: +# - exit_status: '-1' +# limit: 3 diff --git a/.buildkite/pipelines/pull_request/type_check.yml b/.buildkite/pipelines/pull_request/type_check.yml new file mode 100644 index 0000000000000..dc6f8471ff1b2 --- /dev/null +++ b/.buildkite/pipelines/pull_request/type_check.yml @@ -0,0 +1,10 @@ +steps: + - command: .buildkite/scripts/steps/check_types.sh + label: 'Check Types' + agents: + queue: n2-16-spot + timeout_in_minutes: 60 + retry: + automatic: + - exit_status: '-1' + limit: 3 diff --git a/.buildkite/pipelines/pull_request/type_check_selective.yml b/.buildkite/pipelines/pull_request/type_check_selective.yml new file mode 100644 index 0000000000000..7d01f128aac3c --- /dev/null +++ b/.buildkite/pipelines/pull_request/type_check_selective.yml @@ -0,0 +1,10 @@ +steps: + - command: .buildkite/scripts/steps/check_types_commits.sh + label: 'Check Types Commit Diff' + agents: + queue: n2-16-spot + timeout_in_minutes: 60 + retry: + automatic: + - exit_status: '-1' + limit: 3 diff --git a/.buildkite/scripts/pipelines/pull_request/pipeline.ts b/.buildkite/scripts/pipelines/pull_request/pipeline.ts index 80d1312af6e64..37bd89f2a75a7 100644 --- a/.buildkite/scripts/pipelines/pull_request/pipeline.ts +++ b/.buildkite/scripts/pipelines/pull_request/pipeline.ts @@ -59,6 +59,12 @@ const uploadPipeline = (pipelineContent: string | object) => { pipeline.push(getPipeline('.buildkite/pipelines/pull_request/kbn_handlebars.yml')); } + if (GITHUB_PR_LABELS.includes('ci:hard-typecheck')) { + pipeline.push(getPipeline('.buildkite/pipelines/pull_request/type_check.yml')); + } else { + pipeline.push(getPipeline('.buildkite/pipelines/pull_request/type_check_selective.yml')); + } + if ( (await doAnyChangesMatch([ /^src\/plugins\/controls/, diff --git a/.buildkite/scripts/steps/build_api_docs.sh b/.buildkite/scripts/steps/build_api_docs.sh index f86032c902d1a..ba1c2ec7ec94d 100755 --- a/.buildkite/scripts/steps/build_api_docs.sh +++ b/.buildkite/scripts/steps/build_api_docs.sh @@ -4,8 +4,9 @@ set -euo pipefail .buildkite/scripts/bootstrap.sh -echo "--- Run scripts/type_check to ensure that all build available" -node scripts/type_check +# TODO: Enable in #166813 after fixing types +# echo "--- Run scripts/type_check to ensure that all build available" +# node scripts/type_check echo "--- Build API Docs" node --max-old-space-size=12000 scripts/build_api_docs diff --git a/.buildkite/scripts/steps/check_types_commits.sh b/.buildkite/scripts/steps/check_types_commits.sh new file mode 100644 index 0000000000000..0b76d3d8e089a --- /dev/null +++ b/.buildkite/scripts/steps/check_types_commits.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash + +set -euo pipefail + + +if [[ "${CI-}" == "true" ]]; then + .buildkite/scripts/bootstrap.sh + + sha1="${GITHUB_PR_TARGET_BRANCH-}" + sha2="${GITHUB_PR_TRIGGERED_SHA-}" +else + # Script take between 0 and 2 arguments representing two commit SHA's: + # If 0, it will diff HEAD and HEAD^ + # If 1 (SHA1), it will diff SHA1 and SHA1^ + # If 2 (SHA1, SHA2), it will diff SHA1 and SHA2 + sha1="${1-HEAD}" + sha2="${2-$sha1^}" +fi + +uniq_dirs=() +uniq_tsconfigs=() + +echo "Detecting files changed between $sha1 and $sha2..." + +files=($(git diff --name-only $sha1 $sha2)) + +add_dir () { + new_dir=$1 + + if [ ${#uniq_dirs[@]} -gt 0 ]; then + for dir in "${uniq_dirs[@]}" + do + if [[ "$new_dir" == "$dir" ]]; then + return + fi + done + fi + + uniq_dirs+=($new_dir) +} + +add_tsconfig () { + new_tsconfig=$1 + + if [ ${#uniq_tsconfigs[@]} -gt 0 ]; then + for tsconfig in "${uniq_tsconfigs[@]}" + do + if [[ "$new_tsconfig" == "$tsconfig" ]]; then + return + fi + done + fi + + echo " $new_tsconfig" + uniq_tsconfigs+=($new_tsconfig) +} + +contains_tsconfig () { + dir=$1 + tsconfig="$dir/tsconfig.json" + if [ -f "$tsconfig" ]; then + true + else + false + fi +} + +find_tsconfig () { + dir=$1 + + if [[ "$dir" == "." ]]; then + return + fi + + if contains_tsconfig $dir; then + add_tsconfig "$dir/tsconfig.json" + else + find_tsconfig $(dirname -- "$dir") + fi +} + +if [ ${#files[@]} -eq 0 ]; then + echo "No files found!" + exit +fi + +for file in "${files[@]}" +do + dir=$(dirname -- "$file") + + # Ignore buildkite dir because it traverses many kbn packages and emits incorrect results + if [[ "$dir" != .buildkite* ]]; then + add_dir $dir + fi +done + +echo "Looking for related tsconfig.json files..." + +for dir in "${uniq_dirs[@]}" +do + find_tsconfig $dir +done + +if [ ${#uniq_tsconfigs[@]} -eq 0 ]; then + echo "No tsconfig.json files found for changes in $sha1 $sha2" + exit +fi + +echo "Running scripts/type_check for each found tsconfig.json file..." + +for tsconfig in "${uniq_tsconfigs[@]}" +do + node scripts/type_check --project $tsconfig +done \ No newline at end of file diff --git a/package.json b/package.json index 54123db6f2eb7..2749e9b2143c4 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,8 @@ "test:ftr:runner": "node scripts/functional_test_runner", "test:ftr:server": "node scripts/functional_tests_server", "test:jest": "node scripts/jest", - "test:jest_integration": "node scripts/jest_integration" + "test:jest_integration": "node scripts/jest_integration", + "test:type_check": "node scripts/type_check" }, "repository": { "type": "git", diff --git a/packages/kbn-dev-proc-runner/src/proc.ts b/packages/kbn-dev-proc-runner/src/proc.ts index d30a893ae4c75..472d43d66e70d 100644 --- a/packages/kbn-dev-proc-runner/src/proc.ts +++ b/packages/kbn-dev-proc-runner/src/proc.ts @@ -13,7 +13,7 @@ import stripAnsi from 'strip-ansi'; import execa from 'execa'; import * as Rx from 'rxjs'; -import { tap, share, take, mergeMap, map, ignoreElements } from 'rxjs/operators'; +import { tap, share, take, mergeMap, map, ignoreElements, filter } from 'rxjs/operators'; import chalk from 'chalk'; import treeKill from 'tree-kill'; import { ToolingLog } from '@kbn/tooling-log'; @@ -87,13 +87,23 @@ export function startProc(name: string, options: ProcOptions, log: ToolingLog) { const outcome$: Rx.Observable = Rx.race( // observe first exit event - Rx.fromEvent<[number]>(childProcess, 'exit').pipe( + Rx.fromEvent<[number, string]>(childProcess, 'exit').pipe( + filter(([code]) => { + if (stopCalled) { + // when stop was already called, that's a graceful exit, let those events pass. + return true; + } else { + // filtering out further interruption events to prevent `take()` from closing the stream. + return code !== null; + } + }), take(1), map(([code]) => { if (stopCalled) { return null; } - // JVM exits with 143 on SIGTERM and 130 on SIGINT, dont' treat then as errors + + // JVM exits with 143 on SIGTERM and 130 on SIGINT, don't treat them as errors if (code > 0 && !(code === 143 || code === 130)) { throw createFailError(`[${name}] exited with code ${code}`, { exitCode: code, @@ -108,6 +118,12 @@ export function startProc(name: string, options: ProcOptions, log: ToolingLog) { Rx.fromEvent(childProcess, 'error').pipe( take(1), mergeMap((err) => Rx.throwError(err)) + ), + + // observe a promise rejection + Rx.from(childProcess).pipe( + take(1), + mergeMap((err) => Rx.throwError(err)) ) ).pipe(share()); @@ -132,7 +148,7 @@ export function startProc(name: string, options: ProcOptions, log: ToolingLog) { share() ); - const outcomePromise = Rx.merge(lines$.pipe(ignoreElements()), outcome$).toPromise(); + const outcomePromise = Rx.firstValueFrom(Rx.merge(lines$.pipe(ignoreElements()), outcome$)); async function stop(signal: NodeJS.Signals) { if (stopCalled) { diff --git a/packages/kbn-dev-proc-runner/src/proc_runner.ts b/packages/kbn-dev-proc-runner/src/proc_runner.ts index 1226cbeb3eef1..510a96dc043be 100644 --- a/packages/kbn-dev-proc-runner/src/proc_runner.ts +++ b/packages/kbn-dev-proc-runner/src/proc_runner.ts @@ -135,6 +135,9 @@ export class ProcRunner { // wait for process to complete await proc.outcomePromise; } + } catch (e) { + this.log.error(e); + throw e; } finally { // while the procRunner closes promises will resolve/reject because // processes and stopping, but consumers of run() shouldn't have to diff --git a/packages/kbn-ts-type-check-cli/run_type_check_cli.ts b/packages/kbn-ts-type-check-cli/run_type_check_cli.ts index 0295525578952..3f4385118c9c6 100644 --- a/packages/kbn-ts-type-check-cli/run_type_check_cli.ts +++ b/packages/kbn-ts-type-check-cli/run_type_check_cli.ts @@ -124,6 +124,9 @@ run( '--pretty', ...(flagsReader.boolean('verbose') ? ['--verbose'] : []), ], + env: { + NODE_OPTIONS: '--max-old-space-size=8192', + }, cwd: REPO_ROOT, wait: true, }); From 78e887884ccbfd38aebd3aff8ff3efe84534101f Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Mon, 25 Sep 2023 17:58:53 -0700 Subject: [PATCH 40/45] [DOCS] Move preconfigured Tines connector details (#166217) Co-authored-by: Ying Mao --- .../connector-apis-passthru.asciidoc | 33 +++++++++++-- .../connectors/action-types/tines.asciidoc | 35 ++----------- .../pre-configured-connectors.asciidoc | 23 +++++++++ docs/settings/alert-action-settings.asciidoc | 11 ++++- .../plugins/actions/docs/openapi/bundled.json | 49 ++++++++++++++++++- .../plugins/actions/docs/openapi/bundled.yaml | 35 ++++++++++++- .../schemas/config_properties_tines.yaml | 10 +++- .../schemas/secrets_properties_tines.yaml | 12 ++++- ...}@api@actions@connector@{connectorid}.yaml | 2 +- 9 files changed, 165 insertions(+), 45 deletions(-) diff --git a/docs/api-generated/connectors/connector-apis-passthru.asciidoc b/docs/api-generated/connectors/connector-apis-passthru.asciidoc index b68b4e4ca648f..fb1a9b87dbcda 100644 --- a/docs/api-generated/connectors/connector-apis-passthru.asciidoc +++ b/docs/api-generated/connectors/connector-apis-passthru.asciidoc @@ -1015,6 +1015,7 @@ Any modifications made to this file will be overwritten.
  • config_properties_servicenow - Connector request properties for a ServiceNow ITSM connector
  • config_properties_servicenow_itom - Connector request properties for a ServiceNow ITSM connector
  • config_properties_swimlane - Connector request properties for a Swimlane connector
  • +
  • config_properties_tines - Connector request properties for a Tines connector
  • config_properties_torq - Connector request properties for a Torq connector
  • config_properties_webhook - Connector request properties for a Webhook connector
  • config_properties_xmatters - Connector request properties for an xMatters connector
  • @@ -1109,6 +1110,7 @@ Any modifications made to this file will be overwritten.
  • secrets_properties_slack_webhook - Connector secrets properties for a Webhook Slack connector
  • secrets_properties_swimlane - Connector secrets properties for a Swimlane connector
  • secrets_properties_teams - Connector secrets properties for a Microsoft Teams connector
  • +
  • secrets_properties_tines - Connector secrets properties for a Tines connector
  • secrets_properties_torq - Connector secrets properties for a Torq connector
  • secrets_properties_webhook - Connector secrets properties for a Webhook connector
  • secrets_properties_xmatters - Connector secrets properties for an xMatters connector
  • @@ -1128,6 +1130,7 @@ Any modifications made to this file will be overwritten.
  • update_connector_request_slack_webhook - Update Slack connector request
  • update_connector_request_swimlane - Update Swimlane connector request
  • update_connector_request_teams - Update Microsoft Teams connector request
  • +
  • update_connector_request_tines - Update Tines connector request
  • update_connector_request_torq - Update Torq connector request
  • update_connector_request_webhook - Update Webhook connector request
  • update_connector_request_xmatters - Update xMatters connector request
  • @@ -1534,6 +1537,13 @@ Any modifications made to this file will be overwritten.
    mappings (optional)
    +
    +

    config_properties_tines - Connector request properties for a Tines connector Up

    +
    Defines properties for connectors when type is .tines.
    +
    +
    url
    String The Tines tenant URL. If you are using the xpack.actions.allowedHosts setting, make sure this hostname is added to the allowed hosts.
    +
    +

    config_properties_torq - Connector request properties for a Torq connector Up

    Defines properties for connectors when type is .torq.
    @@ -1845,7 +1855,7 @@ Any modifications made to this file will be overwritten.

    connector_response_properties_tines - Connector response properties for a Tines connector Up

    -
    config
    map[String, oas_any_type_not_mapped] Defines properties for connectors when type is .tines.
    +
    config
    connector_type_id
    String The type of connector.
    Enum:
    .tines
    @@ -2113,12 +2123,12 @@ Any modifications made to this file will be overwritten.

    create_connector_request_tines - Create Tines connector request Up

    The Tines connector uses Tines Webhook actions to send events via POST request.
    -
    config
    map[String, oas_any_type_not_mapped] Defines properties for connectors when type is .tines.
    +
    config
    connector_type_id
    String The type of connector.
    Enum:
    .tines
    name
    String The display name for the connector.
    -
    secrets
    map[String, oas_any_type_not_mapped] Defines secrets for connectors when type is .tines.
    +
    secrets
    @@ -2600,6 +2610,14 @@ Any modifications made to this file will be overwritten.
    webhookUrl
    String The URL of the incoming webhook. If you are using the xpack.actions.allowedHosts setting, add the hostname to the allowed hosts.
    +
    +

    secrets_properties_tines - Connector secrets properties for a Tines connector Up

    +
    Defines secrets for connectors when type is .tines.
    +
    +
    email
    String The email used to sign in to Tines.
    +
    token
    String The Tines API token.
    +
    +

    secrets_properties_torq - Connector secrets properties for a Torq connector Up

    Defines secrets for connectors when type is .torq.
    @@ -2765,6 +2783,15 @@ Any modifications made to this file will be overwritten.
    secrets
    +

    update_connector_request_torq - Update Torq connector request Up

    diff --git a/docs/management/connectors/action-types/tines.asciidoc b/docs/management/connectors/action-types/tines.asciidoc index 218de7cb960f2..cdaf56912d0f0 100644 --- a/docs/management/connectors/action-types/tines.asciidoc +++ b/docs/management/connectors/action-types/tines.asciidoc @@ -3,6 +3,10 @@ ++++ Tines ++++ +:frontmatter-description: Add a connector that can use Tines to send events. +:frontmatter-tags-products: [kibana] +:frontmatter-tags-content-type: [how-to] +:frontmatter-tags-user-goals: [configure] The Tines connector uses Tines's https://www.tines.com/docs/actions/types/webhook[Webhook actions] to send events via POST request. @@ -26,37 +30,6 @@ URL:: The Tines tenant URL. If you are using the <> * <> * <> +* <> * <> * <> * <> @@ -530,6 +531,28 @@ xpack.actions.preconfigured: <3> Field mappings for properties such as the alert identifer, severity, and rule name. <4> The API authentication token for HTTP basic authentication. NOTE: This value should be stored in the <>. +[float] +[[preconfigured-tines-configuration]] +==== Tines connectors + +The following example creates a <>: + +[source,text] +-- +xpack.actions.preconfigured: +my-tines: + name: preconfigured-tines-connector-type + actionTypeId: .tines + config: + url: https://some-tenant-2345.tines.com <1> + secrets: + email: some.address@test.com <2> + token: ausergeneratedapitoken <3> +-- +<1> The Tines tenant URL. +<2> The email used to sign in to Tines. +<3> The Tines API token. + [float] [[preconfigured-torq-configuration]] ==== Torq connectors diff --git a/docs/settings/alert-action-settings.asciidoc b/docs/settings/alert-action-settings.asciidoc index b3cd5777edd69..8b05c3108df00 100644 --- a/docs/settings/alert-action-settings.asciidoc +++ b/docs/settings/alert-action-settings.asciidoc @@ -420,7 +420,8 @@ NOTE: If you are using the `xpack.actions.allowedHosts` setting, make sure the h A configuration URL that varies by connector: + -- -* For a <>, specifies the D3 Security API request URL. +* For a <>, specifies the D3 Security API request URL. +* For a <>, specifies the Tines tenant URL. * For a <>, specifies the web service request URL. NOTE: If you are using the `xpack.actions.allowedHosts` setting, make sure this hostname is added to the allowed hosts. @@ -470,7 +471,12 @@ NOTE: The client secret must be URL-encoded. -- `xpack.actions.preconfigured..secrets.email`:: -For a <>, specifies the account email for HTTP basic authentication. +An email address that varies by connector: ++ +-- +* For a <>, specifies the account email for HTTP basic authentication. +* For a <>, specifies the email used to sign in to Tines. +-- `xpack.actions.preconfigured..secrets.password`:: A password secret that varies by connector: @@ -495,6 +501,7 @@ A token secret that varies by connector: -- * For a <>, specifies the D3 Security token. * For a <>, specifies the Slack bot user OAuth token. +* For a <>, specifies the Tines API token. * For a <>, specifies the secret of the webhook authentication header. -- diff --git a/x-pack/plugins/actions/docs/openapi/bundled.json b/x-pack/plugins/actions/docs/openapi/bundled.json index 4039ab6b5a0de..94efaf061fb4f 100644 --- a/x-pack/plugins/actions/docs/openapi/bundled.json +++ b/x-pack/plugins/actions/docs/openapi/bundled.json @@ -514,6 +514,9 @@ { "$ref": "#/components/schemas/update_connector_request_teams" }, + { + "$ref": "#/components/schemas/update_connector_request_tines" + }, { "$ref": "#/components/schemas/update_connector_request_torq" }, @@ -2798,13 +2801,34 @@ "title": "Connector request properties for a Tines connector", "description": "Defines properties for connectors when type is `.tines`.", "type": "object", - "additionalProperties": true + "required": [ + "url" + ], + "properties": { + "url": { + "description": "The Tines tenant URL. If you are using the `xpack.actions.allowedHosts` setting, make sure this hostname is added to the allowed hosts.\n", + "type": "string" + } + } }, "secrets_properties_tines": { "title": "Connector secrets properties for a Tines connector", "description": "Defines secrets for connectors when type is `.tines`.", "type": "object", - "additionalProperties": true + "required": [ + "email", + "token" + ], + "properties": { + "email": { + "description": "The email used to sign in to Tines.", + "type": "string" + }, + "token": { + "description": "The Tines API token.", + "type": "string" + } + } }, "create_connector_request_tines": { "title": "Create Tines connector request", @@ -4337,6 +4361,27 @@ } } }, + "update_connector_request_tines": { + "title": "Update Tines connector request", + "type": "object", + "required": [ + "config", + "name", + "secrets" + ], + "properties": { + "config": { + "$ref": "#/components/schemas/config_properties_tines" + }, + "name": { + "type": "string", + "description": "The display name for the connector." + }, + "secrets": { + "$ref": "#/components/schemas/secrets_properties_tines" + } + } + }, "update_connector_request_torq": { "title": "Update Torq connector request", "type": "object", diff --git a/x-pack/plugins/actions/docs/openapi/bundled.yaml b/x-pack/plugins/actions/docs/openapi/bundled.yaml index 9d1842c4dace9..b1ff36d6f3370 100644 --- a/x-pack/plugins/actions/docs/openapi/bundled.yaml +++ b/x-pack/plugins/actions/docs/openapi/bundled.yaml @@ -266,6 +266,7 @@ paths: - $ref: '#/components/schemas/update_connector_request_slack_webhook' - $ref: '#/components/schemas/update_connector_request_swimlane' - $ref: '#/components/schemas/update_connector_request_teams' + - $ref: '#/components/schemas/update_connector_request_tines' - $ref: '#/components/schemas/update_connector_request_torq' - $ref: '#/components/schemas/update_connector_request_webhook' - $ref: '#/components/schemas/update_connector_request_xmatters' @@ -1888,12 +1889,27 @@ components: title: Connector request properties for a Tines connector description: Defines properties for connectors when type is `.tines`. type: object - additionalProperties: true + required: + - url + properties: + url: + description: | + The Tines tenant URL. If you are using the `xpack.actions.allowedHosts` setting, make sure this hostname is added to the allowed hosts. + type: string secrets_properties_tines: title: Connector secrets properties for a Tines connector description: Defines secrets for connectors when type is `.tines`. type: object - additionalProperties: true + required: + - email + - token + properties: + email: + description: The email used to sign in to Tines. + type: string + token: + description: The Tines API token. + type: string create_connector_request_tines: title: Create Tines connector request description: | @@ -3003,6 +3019,21 @@ components: description: The display name for the connector. secrets: $ref: '#/components/schemas/secrets_properties_teams' + update_connector_request_tines: + title: Update Tines connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/config_properties_tines' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/secrets_properties_tines' update_connector_request_torq: title: Update Torq connector request type: object diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_tines.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_tines.yaml index 336a312d9ac8e..2bb480d7c18b2 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_tines.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_tines.yaml @@ -1,5 +1,11 @@ title: Connector request properties for a Tines connector description: Defines properties for connectors when type is `.tines`. type: object -additionalProperties: true -# TO-DO: Add the properties for this connector. \ No newline at end of file +required: + - url +properties: + url: + description: > + The Tines tenant URL. + If you are using the `xpack.actions.allowedHosts` setting, make sure this hostname is added to the allowed hosts. + type: string \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/secrets_properties_tines.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/secrets_properties_tines.yaml index 2373f14beae50..e480505dc1938 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/secrets_properties_tines.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/secrets_properties_tines.yaml @@ -1,5 +1,13 @@ title: Connector secrets properties for a Tines connector description: Defines secrets for connectors when type is `.tines`. type: object -additionalProperties: true -# TO-DO: Add the properties for this connector. \ No newline at end of file +required: + - email + - token +properties: + email: + description: The email used to sign in to Tines. + type: string + token: + description: The Tines API token. + type: string \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml index ad93b5076639a..d85e38cff5f75 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml @@ -176,7 +176,7 @@ put: - $ref: '../components/schemas/update_connector_request_slack_webhook.yaml' - $ref: '../components/schemas/update_connector_request_swimlane.yaml' - $ref: '../components/schemas/update_connector_request_teams.yaml' -# - $ref: '../components/schemas/update_connector_request_tines.yaml' + - $ref: '../components/schemas/update_connector_request_tines.yaml' - $ref: '../components/schemas/update_connector_request_torq.yaml' - $ref: '../components/schemas/update_connector_request_webhook.yaml' - $ref: '../components/schemas/update_connector_request_xmatters.yaml' From b3c1ba265f503137d66327f6e0c491859ba75adc Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 26 Sep 2023 00:42:16 -0400 Subject: [PATCH 41/45] [api-docs] 2023-09-26 Daily api_docs build (#167210) Generated by https://buildkite.com/elastic/kibana-api-docs-daily/builds/472 --- api_docs/actions.mdx | 2 +- api_docs/advanced_settings.mdx | 2 +- api_docs/aiops.mdx | 2 +- api_docs/alerting.mdx | 2 +- api_docs/apm.mdx | 2 +- api_docs/apm_data_access.mdx | 2 +- api_docs/asset_manager.mdx | 2 +- api_docs/banners.mdx | 2 +- api_docs/bfetch.mdx | 2 +- api_docs/canvas.mdx | 2 +- api_docs/cases.mdx | 2 +- api_docs/charts.mdx | 2 +- api_docs/cloud.mdx | 2 +- api_docs/cloud_chat.mdx | 2 +- api_docs/cloud_chat_provider.mdx | 2 +- api_docs/cloud_data_migration.mdx | 2 +- api_docs/cloud_defend.mdx | 2 +- api_docs/cloud_experiments.mdx | 2 +- api_docs/cloud_security_posture.mdx | 2 +- api_docs/console.mdx | 2 +- api_docs/content_management.mdx | 2 +- api_docs/controls.mdx | 2 +- api_docs/custom_integrations.mdx | 2 +- api_docs/dashboard.mdx | 2 +- api_docs/dashboard_enhanced.mdx | 2 +- api_docs/data.mdx | 2 +- api_docs/data_query.mdx | 2 +- api_docs/data_search.mdx | 2 +- api_docs/data_view_editor.mdx | 2 +- api_docs/data_view_field_editor.mdx | 2 +- api_docs/data_view_management.mdx | 2 +- api_docs/data_views.mdx | 2 +- api_docs/data_visualizer.mdx | 2 +- api_docs/deprecations_by_api.mdx | 4 +- 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/ecs_data_quality_dashboard.mdx | 2 +- api_docs/elastic_assistant.mdx | 2 +- api_docs/embeddable.mdx | 2 +- api_docs/embeddable_enhanced.mdx | 2 +- api_docs/encrypted_saved_objects.mdx | 2 +- api_docs/enterprise_search.devdocs.json | 15 -- api_docs/enterprise_search.mdx | 4 +- api_docs/es_ui_shared.mdx | 2 +- api_docs/event_annotation.mdx | 2 +- api_docs/event_annotation_listing.mdx | 2 +- api_docs/event_log.mdx | 2 +- api_docs/exploratory_view.mdx | 2 +- api_docs/expression_error.mdx | 2 +- api_docs/expression_gauge.mdx | 2 +- api_docs/expression_heatmap.mdx | 2 +- api_docs/expression_image.mdx | 2 +- api_docs/expression_legacy_metric_vis.mdx | 2 +- api_docs/expression_metric.mdx | 2 +- api_docs/expression_metric_vis.mdx | 2 +- api_docs/expression_partition_vis.mdx | 2 +- api_docs/expression_repeat_image.mdx | 2 +- api_docs/expression_reveal_image.mdx | 2 +- api_docs/expression_shape.mdx | 2 +- api_docs/expression_tagcloud.mdx | 2 +- api_docs/expression_x_y.mdx | 2 +- api_docs/expressions.mdx | 2 +- api_docs/features.mdx | 2 +- api_docs/field_formats.mdx | 2 +- api_docs/file_upload.mdx | 2 +- api_docs/files.mdx | 2 +- api_docs/files_management.mdx | 2 +- api_docs/fleet.devdocs.json | 45 ++-- api_docs/fleet.mdx | 4 +- api_docs/global_search.mdx | 2 +- api_docs/guided_onboarding.mdx | 2 +- api_docs/home.mdx | 2 +- api_docs/image_embeddable.mdx | 2 +- api_docs/index_lifecycle_management.mdx | 2 +- api_docs/index_management.mdx | 2 +- api_docs/infra.mdx | 2 +- api_docs/inspector.mdx | 2 +- api_docs/interactive_setup.mdx | 2 +- api_docs/kbn_ace.mdx | 2 +- api_docs/kbn_aiops_components.mdx | 2 +- api_docs/kbn_aiops_utils.mdx | 2 +- .../kbn_alerting_api_integration_helpers.mdx | 2 +- api_docs/kbn_alerting_state_types.mdx | 2 +- api_docs/kbn_alerts_as_data_utils.mdx | 2 +- api_docs/kbn_alerts_ui_shared.mdx | 2 +- api_docs/kbn_analytics.mdx | 2 +- api_docs/kbn_analytics_client.mdx | 2 +- ..._analytics_shippers_elastic_v3_browser.mdx | 2 +- ...n_analytics_shippers_elastic_v3_common.mdx | 2 +- ...n_analytics_shippers_elastic_v3_server.mdx | 2 +- api_docs/kbn_analytics_shippers_fullstory.mdx | 2 +- api_docs/kbn_analytics_shippers_gainsight.mdx | 2 +- api_docs/kbn_apm_config_loader.mdx | 2 +- api_docs/kbn_apm_synthtrace.mdx | 2 +- api_docs/kbn_apm_synthtrace_client.mdx | 2 +- api_docs/kbn_apm_utils.mdx | 2 +- api_docs/kbn_axe_config.mdx | 2 +- api_docs/kbn_cases_components.mdx | 2 +- api_docs/kbn_cell_actions.mdx | 2 +- api_docs/kbn_chart_expressions_common.mdx | 2 +- api_docs/kbn_chart_icons.mdx | 2 +- api_docs/kbn_ci_stats_core.mdx | 2 +- api_docs/kbn_ci_stats_performance_metrics.mdx | 2 +- api_docs/kbn_ci_stats_reporter.mdx | 2 +- api_docs/kbn_cli_dev_mode.mdx | 2 +- api_docs/kbn_code_editor.mdx | 2 +- api_docs/kbn_code_editor_mocks.mdx | 2 +- api_docs/kbn_coloring.mdx | 2 +- api_docs/kbn_config.mdx | 2 +- api_docs/kbn_config_mocks.mdx | 2 +- api_docs/kbn_config_schema.mdx | 2 +- .../kbn_content_management_content_editor.mdx | 2 +- ...tent_management_tabbed_table_list_view.mdx | 2 +- ...kbn_content_management_table_list_view.mdx | 2 +- ...ntent_management_table_list_view_table.mdx | 2 +- api_docs/kbn_content_management_utils.mdx | 2 +- api_docs/kbn_core_analytics_browser.mdx | 2 +- .../kbn_core_analytics_browser_internal.mdx | 2 +- api_docs/kbn_core_analytics_browser_mocks.mdx | 2 +- api_docs/kbn_core_analytics_server.mdx | 2 +- .../kbn_core_analytics_server_internal.mdx | 2 +- api_docs/kbn_core_analytics_server_mocks.mdx | 2 +- api_docs/kbn_core_application_browser.mdx | 2 +- .../kbn_core_application_browser_internal.mdx | 2 +- .../kbn_core_application_browser_mocks.mdx | 2 +- api_docs/kbn_core_application_common.mdx | 2 +- api_docs/kbn_core_apps_browser_internal.mdx | 2 +- api_docs/kbn_core_apps_browser_mocks.mdx | 2 +- api_docs/kbn_core_apps_server_internal.mdx | 2 +- api_docs/kbn_core_base_browser_mocks.mdx | 2 +- api_docs/kbn_core_base_common.mdx | 2 +- api_docs/kbn_core_base_server_internal.mdx | 2 +- api_docs/kbn_core_base_server_mocks.mdx | 2 +- .../kbn_core_capabilities_browser_mocks.mdx | 2 +- api_docs/kbn_core_capabilities_common.mdx | 2 +- api_docs/kbn_core_capabilities_server.mdx | 2 +- .../kbn_core_capabilities_server_mocks.mdx | 2 +- api_docs/kbn_core_chrome_browser.mdx | 2 +- api_docs/kbn_core_chrome_browser_mocks.mdx | 2 +- api_docs/kbn_core_config_server_internal.mdx | 2 +- api_docs/kbn_core_custom_branding_browser.mdx | 2 +- ..._core_custom_branding_browser_internal.mdx | 2 +- ...kbn_core_custom_branding_browser_mocks.mdx | 2 +- api_docs/kbn_core_custom_branding_common.mdx | 2 +- api_docs/kbn_core_custom_branding_server.mdx | 2 +- ...n_core_custom_branding_server_internal.mdx | 2 +- .../kbn_core_custom_branding_server_mocks.mdx | 2 +- api_docs/kbn_core_deprecations_browser.mdx | 2 +- ...kbn_core_deprecations_browser_internal.mdx | 2 +- .../kbn_core_deprecations_browser_mocks.mdx | 2 +- api_docs/kbn_core_deprecations_common.mdx | 2 +- api_docs/kbn_core_deprecations_server.mdx | 2 +- .../kbn_core_deprecations_server_internal.mdx | 2 +- .../kbn_core_deprecations_server_mocks.mdx | 2 +- api_docs/kbn_core_doc_links_browser.mdx | 2 +- api_docs/kbn_core_doc_links_browser_mocks.mdx | 2 +- api_docs/kbn_core_doc_links_server.mdx | 2 +- api_docs/kbn_core_doc_links_server_mocks.mdx | 2 +- ...e_elasticsearch_client_server_internal.mdx | 2 +- ...core_elasticsearch_client_server_mocks.mdx | 2 +- api_docs/kbn_core_elasticsearch_server.mdx | 2 +- ...kbn_core_elasticsearch_server_internal.mdx | 2 +- .../kbn_core_elasticsearch_server_mocks.mdx | 2 +- .../kbn_core_environment_server_internal.mdx | 2 +- .../kbn_core_environment_server_mocks.mdx | 2 +- .../kbn_core_execution_context_browser.mdx | 2 +- ...ore_execution_context_browser_internal.mdx | 2 +- ...n_core_execution_context_browser_mocks.mdx | 2 +- .../kbn_core_execution_context_common.mdx | 2 +- .../kbn_core_execution_context_server.mdx | 2 +- ...core_execution_context_server_internal.mdx | 2 +- ...bn_core_execution_context_server_mocks.mdx | 2 +- api_docs/kbn_core_fatal_errors_browser.mdx | 2 +- .../kbn_core_fatal_errors_browser_mocks.mdx | 2 +- api_docs/kbn_core_http_browser.mdx | 2 +- api_docs/kbn_core_http_browser_internal.mdx | 2 +- api_docs/kbn_core_http_browser_mocks.mdx | 2 +- api_docs/kbn_core_http_common.mdx | 2 +- .../kbn_core_http_context_server_mocks.mdx | 2 +- ...re_http_request_handler_context_server.mdx | 2 +- api_docs/kbn_core_http_resources_server.mdx | 2 +- ...bn_core_http_resources_server_internal.mdx | 2 +- .../kbn_core_http_resources_server_mocks.mdx | 2 +- .../kbn_core_http_router_server_internal.mdx | 2 +- .../kbn_core_http_router_server_mocks.mdx | 2 +- api_docs/kbn_core_http_server.devdocs.json | 8 + 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 +- api_docs/kbn_core_plugins_server.mdx | 2 +- api_docs/kbn_core_plugins_server_mocks.mdx | 2 +- api_docs/kbn_core_preboot_server.mdx | 2 +- api_docs/kbn_core_preboot_server_mocks.mdx | 2 +- api_docs/kbn_core_rendering_browser_mocks.mdx | 2 +- .../kbn_core_rendering_server_internal.mdx | 2 +- api_docs/kbn_core_rendering_server_mocks.mdx | 2 +- api_docs/kbn_core_root_server_internal.mdx | 2 +- .../kbn_core_saved_objects_api_browser.mdx | 2 +- .../kbn_core_saved_objects_api_server.mdx | 2 +- ...bn_core_saved_objects_api_server_mocks.mdx | 2 +- ...ore_saved_objects_base_server_internal.mdx | 2 +- ...n_core_saved_objects_base_server_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_browser.mdx | 2 +- ...bn_core_saved_objects_browser_internal.mdx | 2 +- .../kbn_core_saved_objects_browser_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_common.mdx | 2 +- ..._objects_import_export_server_internal.mdx | 2 +- ...ved_objects_import_export_server_mocks.mdx | 2 +- ...aved_objects_migration_server_internal.mdx | 2 +- ...e_saved_objects_migration_server_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_server.mdx | 2 +- ...kbn_core_saved_objects_server_internal.mdx | 2 +- .../kbn_core_saved_objects_server_mocks.mdx | 2 +- .../kbn_core_saved_objects_utils_server.mdx | 2 +- api_docs/kbn_core_status_common.mdx | 2 +- api_docs/kbn_core_status_common_internal.mdx | 2 +- api_docs/kbn_core_status_server.mdx | 2 +- api_docs/kbn_core_status_server_internal.mdx | 2 +- api_docs/kbn_core_status_server_mocks.mdx | 2 +- ...core_test_helpers_deprecations_getters.mdx | 2 +- ...n_core_test_helpers_http_setup_browser.mdx | 2 +- api_docs/kbn_core_test_helpers_kbn_server.mdx | 2 +- ...n_core_test_helpers_so_type_serializer.mdx | 2 +- api_docs/kbn_core_test_helpers_test_utils.mdx | 2 +- api_docs/kbn_core_theme_browser.mdx | 2 +- api_docs/kbn_core_theme_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_browser.mdx | 2 +- .../kbn_core_ui_settings_browser_internal.mdx | 2 +- .../kbn_core_ui_settings_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_common.mdx | 2 +- api_docs/kbn_core_ui_settings_server.mdx | 2 +- .../kbn_core_ui_settings_server_internal.mdx | 2 +- .../kbn_core_ui_settings_server_mocks.mdx | 2 +- api_docs/kbn_core_usage_data_server.mdx | 2 +- .../kbn_core_usage_data_server_internal.mdx | 2 +- api_docs/kbn_core_usage_data_server_mocks.mdx | 2 +- api_docs/kbn_core_user_settings_server.mdx | 2 +- ...kbn_core_user_settings_server_internal.mdx | 2 +- .../kbn_core_user_settings_server_mocks.mdx | 2 +- api_docs/kbn_crypto.mdx | 2 +- api_docs/kbn_crypto_browser.mdx | 2 +- api_docs/kbn_custom_integrations.mdx | 2 +- api_docs/kbn_cypress_config.mdx | 2 +- api_docs/kbn_data_service.mdx | 2 +- api_docs/kbn_datemath.mdx | 2 +- api_docs/kbn_deeplinks_analytics.mdx | 2 +- api_docs/kbn_deeplinks_devtools.mdx | 2 +- api_docs/kbn_deeplinks_management.mdx | 2 +- api_docs/kbn_deeplinks_ml.mdx | 2 +- api_docs/kbn_deeplinks_observability.mdx | 2 +- api_docs/kbn_deeplinks_search.mdx | 2 +- api_docs/kbn_default_nav_analytics.mdx | 2 +- api_docs/kbn_default_nav_devtools.mdx | 2 +- api_docs/kbn_default_nav_management.mdx | 2 +- api_docs/kbn_default_nav_ml.mdx | 2 +- api_docs/kbn_dev_cli_errors.mdx | 2 +- api_docs/kbn_dev_cli_runner.devdocs.json | 14 ++ api_docs/kbn_dev_cli_runner.mdx | 4 +- api_docs/kbn_dev_proc_runner.mdx | 2 +- api_docs/kbn_dev_utils.mdx | 2 +- api_docs/kbn_discover_utils.mdx | 2 +- api_docs/kbn_doc_links.mdx | 2 +- api_docs/kbn_docs_utils.mdx | 2 +- api_docs/kbn_dom_drag_drop.mdx | 2 +- api_docs/kbn_ebt_tools.mdx | 2 +- api_docs/kbn_ecs.mdx | 2 +- api_docs/kbn_ecs_data_quality_dashboard.mdx | 2 +- api_docs/kbn_elastic_assistant.mdx | 2 +- api_docs/kbn_es.mdx | 2 +- api_docs/kbn_es_archiver.mdx | 2 +- api_docs/kbn_es_errors.mdx | 2 +- api_docs/kbn_es_query.mdx | 2 +- api_docs/kbn_es_types.mdx | 2 +- api_docs/kbn_eslint_plugin_imports.mdx | 2 +- api_docs/kbn_event_annotation_common.mdx | 2 +- api_docs/kbn_event_annotation_components.mdx | 2 +- api_docs/kbn_expandable_flyout.mdx | 2 +- api_docs/kbn_field_types.mdx | 2 +- api_docs/kbn_find_used_node_modules.mdx | 2 +- .../kbn_ftr_common_functional_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_generate_csv_types.mdx | 2 +- api_docs/kbn_guided_onboarding.mdx | 2 +- api_docs/kbn_handlebars.mdx | 2 +- api_docs/kbn_hapi_mocks.mdx | 2 +- api_docs/kbn_health_gateway_server.mdx | 2 +- api_docs/kbn_home_sample_data_card.mdx | 2 +- api_docs/kbn_home_sample_data_tab.mdx | 2 +- api_docs/kbn_i18n.mdx | 2 +- api_docs/kbn_i18n_react.mdx | 2 +- api_docs/kbn_import_resolver.mdx | 2 +- api_docs/kbn_infra_forge.mdx | 2 +- api_docs/kbn_interpreter.mdx | 2 +- api_docs/kbn_io_ts_utils.mdx | 2 +- api_docs/kbn_jest_serializers.mdx | 2 +- api_docs/kbn_journeys.mdx | 2 +- api_docs/kbn_json_ast.mdx | 2 +- api_docs/kbn_kibana_manifest_schema.mdx | 2 +- .../kbn_language_documentation_popover.mdx | 2 +- api_docs/kbn_lens_embeddable_utils.mdx | 2 +- api_docs/kbn_logging.mdx | 2 +- api_docs/kbn_logging_mocks.mdx | 2 +- api_docs/kbn_managed_vscode_config.mdx | 2 +- api_docs/kbn_management_cards_navigation.mdx | 2 +- ...gement_settings_components_field_input.mdx | 2 +- ...nagement_settings_components_field_row.mdx | 2 +- ...n_management_settings_field_definition.mdx | 2 +- api_docs/kbn_management_settings_ids.mdx | 2 +- ...n_management_settings_section_registry.mdx | 2 +- api_docs/kbn_management_settings_types.mdx | 2 +- .../kbn_management_settings_utilities.mdx | 2 +- api_docs/kbn_management_storybook_config.mdx | 2 +- api_docs/kbn_mapbox_gl.mdx | 2 +- api_docs/kbn_maps_vector_tile_utils.mdx | 2 +- api_docs/kbn_ml_agg_utils.mdx | 2 +- api_docs/kbn_ml_anomaly_utils.mdx | 2 +- api_docs/kbn_ml_category_validator.mdx | 2 +- .../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 +- .../kbn_ml_trained_models_utils.devdocs.json | 219 ++++++++++++++++- api_docs/kbn_ml_trained_models_utils.mdx | 7 +- api_docs/kbn_ml_url_state.mdx | 2 +- api_docs/kbn_monaco.mdx | 2 +- api_docs/kbn_object_versioning.mdx | 2 +- api_docs/kbn_observability_alert_details.mdx | 2 +- api_docs/kbn_openapi_generator.devdocs.json | 143 +++++++++++ api_docs/kbn_openapi_generator.mdx | 33 +++ api_docs/kbn_optimizer.mdx | 2 +- api_docs/kbn_optimizer_webpack_helpers.mdx | 2 +- api_docs/kbn_osquery_io_ts_types.mdx | 2 +- ..._performance_testing_dataset_extractor.mdx | 2 +- api_docs/kbn_plugin_generator.mdx | 2 +- api_docs/kbn_plugin_helpers.mdx | 2 +- api_docs/kbn_profiling_utils.mdx | 2 +- api_docs/kbn_random_sampling.mdx | 2 +- api_docs/kbn_react_field.mdx | 2 +- api_docs/kbn_react_kibana_context_common.mdx | 2 +- api_docs/kbn_react_kibana_context_render.mdx | 2 +- api_docs/kbn_react_kibana_context_root.mdx | 2 +- api_docs/kbn_react_kibana_context_styled.mdx | 2 +- api_docs/kbn_react_kibana_context_theme.mdx | 2 +- api_docs/kbn_react_kibana_mount.mdx | 2 +- api_docs/kbn_repo_file_maps.mdx | 2 +- api_docs/kbn_repo_linter.mdx | 2 +- api_docs/kbn_repo_path.mdx | 2 +- api_docs/kbn_repo_source_classifier.mdx | 2 +- api_docs/kbn_reporting_common.mdx | 2 +- api_docs/kbn_rison.mdx | 2 +- api_docs/kbn_rrule.mdx | 2 +- api_docs/kbn_rule_data_utils.mdx | 2 +- api_docs/kbn_saved_objects_settings.mdx | 2 +- api_docs/kbn_search_api_panels.mdx | 2 +- api_docs/kbn_search_connectors.mdx | 2 +- api_docs/kbn_search_response_warnings.mdx | 2 +- api_docs/kbn_security_solution_features.mdx | 2 +- api_docs/kbn_security_solution_navigation.mdx | 2 +- api_docs/kbn_security_solution_side_nav.mdx | 2 +- ...kbn_security_solution_storybook_config.mdx | 2 +- .../kbn_securitysolution_autocomplete.mdx | 2 +- api_docs/kbn_securitysolution_data_table.mdx | 2 +- api_docs/kbn_securitysolution_ecs.mdx | 2 +- api_docs/kbn_securitysolution_es_utils.mdx | 2 +- ...ritysolution_exception_list_components.mdx | 2 +- api_docs/kbn_securitysolution_grouping.mdx | 2 +- api_docs/kbn_securitysolution_hook_utils.mdx | 2 +- ..._securitysolution_io_ts_alerting_types.mdx | 2 +- .../kbn_securitysolution_io_ts_list_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_utils.mdx | 2 +- api_docs/kbn_securitysolution_list_api.mdx | 2 +- .../kbn_securitysolution_list_constants.mdx | 2 +- api_docs/kbn_securitysolution_list_hooks.mdx | 2 +- api_docs/kbn_securitysolution_list_utils.mdx | 2 +- api_docs/kbn_securitysolution_rules.mdx | 2 +- api_docs/kbn_securitysolution_t_grid.mdx | 2 +- api_docs/kbn_securitysolution_utils.mdx | 2 +- api_docs/kbn_server_http_tools.mdx | 2 +- api_docs/kbn_server_route_repository.mdx | 2 +- api_docs/kbn_serverless_common_settings.mdx | 2 +- .../kbn_serverless_observability_settings.mdx | 2 +- api_docs/kbn_serverless_project_switcher.mdx | 2 +- api_docs/kbn_serverless_search_settings.mdx | 2 +- api_docs/kbn_serverless_security_settings.mdx | 2 +- api_docs/kbn_serverless_storybook_config.mdx | 2 +- api_docs/kbn_shared_svg.mdx | 2 +- api_docs/kbn_shared_ux_avatar_solution.mdx | 2 +- ...ared_ux_avatar_user_profile_components.mdx | 2 +- .../kbn_shared_ux_button_exit_full_screen.mdx | 2 +- ...hared_ux_button_exit_full_screen_mocks.mdx | 2 +- .../kbn_shared_ux_button_toolbar.devdocs.json | 14 +- 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_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 +- ...hared_ux_prompt_no_data_views.devdocs.json | 2 +- .../kbn_shared_ux_prompt_no_data_views.mdx | 2 +- ...n_shared_ux_prompt_no_data_views_mocks.mdx | 2 +- api_docs/kbn_shared_ux_prompt_not_found.mdx | 2 +- api_docs/kbn_shared_ux_router.mdx | 2 +- api_docs/kbn_shared_ux_router_mocks.mdx | 2 +- api_docs/kbn_shared_ux_storybook_config.mdx | 2 +- api_docs/kbn_shared_ux_storybook_mock.mdx | 2 +- api_docs/kbn_shared_ux_utility.mdx | 2 +- api_docs/kbn_slo_schema.mdx | 2 +- api_docs/kbn_some_dev_log.mdx | 2 +- api_docs/kbn_std.mdx | 2 +- api_docs/kbn_stdio_dev_helpers.mdx | 2 +- api_docs/kbn_storybook.mdx | 2 +- api_docs/kbn_subscription_tracking.mdx | 2 +- api_docs/kbn_telemetry_tools.mdx | 2 +- api_docs/kbn_test.devdocs.json | 18 +- api_docs/kbn_test.mdx | 4 +- api_docs/kbn_test_jest_helpers.mdx | 2 +- api_docs/kbn_test_subj_selector.mdx | 2 +- api_docs/kbn_text_based_editor.mdx | 2 +- api_docs/kbn_tooling_log.mdx | 2 +- api_docs/kbn_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_url_state.mdx | 2 +- api_docs/kbn_use_tracked_promise.mdx | 2 +- api_docs/kbn_user_profile_components.mdx | 2 +- api_docs/kbn_utility_types.mdx | 2 +- api_docs/kbn_utility_types_jest.mdx | 2 +- api_docs/kbn_utils.mdx | 2 +- ...n_visualization_ui_components.devdocs.json | 4 +- api_docs/kbn_visualization_ui_components.mdx | 2 +- api_docs/kbn_xstate_utils.mdx | 2 +- api_docs/kbn_yarn_lock_validator.mdx | 2 +- api_docs/kibana_overview.mdx | 2 +- api_docs/kibana_react.devdocs.json | 228 ------------------ api_docs/kibana_react.mdx | 4 +- api_docs/kibana_utils.mdx | 2 +- api_docs/kubernetes_security.mdx | 2 +- api_docs/lens.mdx | 2 +- api_docs/license_api_guard.mdx | 2 +- api_docs/license_management.mdx | 2 +- api_docs/licensing.mdx | 2 +- api_docs/lists.mdx | 2 +- api_docs/log_explorer.mdx | 2 +- api_docs/logs_shared.mdx | 2 +- api_docs/management.mdx | 2 +- api_docs/maps.mdx | 2 +- api_docs/maps_ems.mdx | 2 +- api_docs/metrics_data_access.mdx | 2 +- api_docs/ml.devdocs.json | 24 ++ api_docs/ml.mdx | 7 +- 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 +- .../observability_a_i_assistant.devdocs.json | 108 +++++++-- api_docs/observability_a_i_assistant.mdx | 2 +- api_docs/observability_log_explorer.mdx | 2 +- api_docs/observability_onboarding.mdx | 2 +- api_docs/observability_shared.devdocs.json | 45 ++++ api_docs/observability_shared.mdx | 4 +- api_docs/osquery.mdx | 2 +- api_docs/painless_lab.mdx | 2 +- api_docs/plugin_directory.mdx | 27 ++- api_docs/presentation_util.mdx | 2 +- api_docs/profiling.devdocs.json | 18 +- api_docs/profiling.mdx | 7 +- api_docs/profiling_data_access.devdocs.json | 4 +- api_docs/profiling_data_access.mdx | 4 +- api_docs/remote_clusters.mdx | 2 +- api_docs/reporting.mdx | 2 +- api_docs/rollup.mdx | 2 +- api_docs/rule_registry.mdx | 2 +- api_docs/runtime_fields.mdx | 2 +- api_docs/saved_objects.mdx | 2 +- api_docs/saved_objects_finder.mdx | 2 +- api_docs/saved_objects_management.mdx | 2 +- api_docs/saved_objects_tagging.mdx | 2 +- api_docs/saved_objects_tagging_oss.mdx | 2 +- api_docs/saved_search.mdx | 2 +- api_docs/screenshot_mode.mdx | 2 +- api_docs/screenshotting.mdx | 2 +- api_docs/security.mdx | 2 +- api_docs/security_solution.mdx | 2 +- api_docs/security_solution_ess.mdx | 2 +- api_docs/security_solution_serverless.mdx | 2 +- api_docs/serverless.mdx | 2 +- api_docs/serverless_observability.mdx | 2 +- api_docs/serverless_search.mdx | 2 +- api_docs/session_view.mdx | 2 +- api_docs/share.mdx | 2 +- api_docs/snapshot_restore.mdx | 2 +- api_docs/spaces.mdx | 2 +- api_docs/stack_alerts.mdx | 2 +- api_docs/stack_connectors.mdx | 2 +- api_docs/task_manager.mdx | 2 +- api_docs/telemetry.mdx | 2 +- api_docs/telemetry_collection_manager.mdx | 2 +- api_docs/telemetry_collection_xpack.mdx | 2 +- api_docs/telemetry_management_section.mdx | 2 +- api_docs/text_based_languages.mdx | 2 +- api_docs/threat_intelligence.mdx | 2 +- api_docs/timelines.mdx | 2 +- api_docs/transform.mdx | 2 +- api_docs/triggers_actions_ui.mdx | 2 +- api_docs/ui_actions.mdx | 2 +- api_docs/ui_actions_enhanced.mdx | 2 +- api_docs/unified_doc_viewer.mdx | 2 +- api_docs/unified_histogram.mdx | 2 +- api_docs/unified_search.mdx | 2 +- api_docs/unified_search_autocomplete.mdx | 2 +- api_docs/uptime.mdx | 2 +- api_docs/url_forwarding.mdx | 2 +- api_docs/usage_collection.mdx | 2 +- api_docs/ux.mdx | 2 +- api_docs/vis_default_editor.mdx | 2 +- api_docs/vis_type_gauge.mdx | 2 +- api_docs/vis_type_heatmap.mdx | 2 +- api_docs/vis_type_pie.mdx | 2 +- api_docs/vis_type_table.mdx | 2 +- api_docs/vis_type_timelion.mdx | 2 +- api_docs/vis_type_timeseries.mdx | 2 +- api_docs/vis_type_vega.mdx | 2 +- api_docs/vis_type_vislib.mdx | 2 +- api_docs/vis_type_xy.mdx | 2 +- api_docs/visualizations.mdx | 2 +- 607 files changed, 1241 insertions(+), 939 deletions(-) create mode 100644 api_docs/kbn_openapi_generator.devdocs.json create mode 100644 api_docs/kbn_openapi_generator.mdx diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index dab0da20342e7..ec6acc7abe98d 100644 --- a/api_docs/actions.mdx +++ b/api_docs/actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/actions title: "actions" image: https://source.unsplash.com/400x175/?github description: API docs for the actions plugin -date: 2023-09-25 +date: 2023-09-26 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 8cb0ef5bb4524..529e5f913ac7e 100644 --- a/api_docs/advanced_settings.mdx +++ b/api_docs/advanced_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/advancedSettings title: "advancedSettings" image: https://source.unsplash.com/400x175/?github description: API docs for the advancedSettings plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index b226186c3d397..97cc1d7cb21de 100644 --- a/api_docs/aiops.mdx +++ b/api_docs/aiops.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiops title: "aiops" image: https://source.unsplash.com/400x175/?github description: API docs for the aiops plugin -date: 2023-09-25 +date: 2023-09-26 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 796378d9cd4a5..07c5991090f05 100644 --- a/api_docs/alerting.mdx +++ b/api_docs/alerting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/alerting title: "alerting" image: https://source.unsplash.com/400x175/?github description: API docs for the alerting plugin -date: 2023-09-25 +date: 2023-09-26 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 0a39b5e552aaa..0c90cf79c9974 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apm title: "apm" image: https://source.unsplash.com/400x175/?github description: API docs for the apm plugin -date: 2023-09-25 +date: 2023-09-26 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 63d16aa0e2bcf..00c1bdefa5cfb 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; diff --git a/api_docs/asset_manager.mdx b/api_docs/asset_manager.mdx index 5d045c726d11b..11fb62a7fde7d 100644 --- a/api_docs/asset_manager.mdx +++ b/api_docs/asset_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/assetManager title: "assetManager" image: https://source.unsplash.com/400x175/?github description: API docs for the assetManager plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'assetManager'] --- import assetManagerObj from './asset_manager.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index 9b498aefcc82c..a9cbbab0920e2 100644 --- a/api_docs/banners.mdx +++ b/api_docs/banners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/banners title: "banners" image: https://source.unsplash.com/400x175/?github description: API docs for the banners plugin -date: 2023-09-25 +date: 2023-09-26 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 ed8902cb5eab1..421ac4b1bdfc6 100644 --- a/api_docs/bfetch.mdx +++ b/api_docs/bfetch.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/bfetch title: "bfetch" image: https://source.unsplash.com/400x175/?github description: API docs for the bfetch plugin -date: 2023-09-25 +date: 2023-09-26 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 78c5c53d74bdd..8c71da99962b1 100644 --- a/api_docs/canvas.mdx +++ b/api_docs/canvas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/canvas title: "canvas" image: https://source.unsplash.com/400x175/?github description: API docs for the canvas plugin -date: 2023-09-25 +date: 2023-09-26 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 e5690d05becce..b26e5fdc1bec6 100644 --- a/api_docs/cases.mdx +++ b/api_docs/cases.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cases title: "cases" image: https://source.unsplash.com/400x175/?github description: API docs for the cases plugin -date: 2023-09-25 +date: 2023-09-26 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 5ebd59d7b500f..d6edcef304cfa 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/charts title: "charts" image: https://source.unsplash.com/400x175/?github description: API docs for the charts plugin -date: 2023-09-25 +date: 2023-09-26 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 5895b73947f55..8770378fa7713 100644 --- a/api_docs/cloud.mdx +++ b/api_docs/cloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloud title: "cloud" image: https://source.unsplash.com/400x175/?github description: API docs for the cloud plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_chat.mdx b/api_docs/cloud_chat.mdx index 4eba8503139ab..d3be97d80040a 100644 --- a/api_docs/cloud_chat.mdx +++ b/api_docs/cloud_chat.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudChat title: "cloudChat" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudChat plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudChat'] --- import cloudChatObj from './cloud_chat.devdocs.json'; diff --git a/api_docs/cloud_chat_provider.mdx b/api_docs/cloud_chat_provider.mdx index bec0cd2b78006..bd056a9cab82c 100644 --- a/api_docs/cloud_chat_provider.mdx +++ b/api_docs/cloud_chat_provider.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudChatProvider title: "cloudChatProvider" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudChatProvider plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudChatProvider'] --- import cloudChatProviderObj from './cloud_chat_provider.devdocs.json'; diff --git a/api_docs/cloud_data_migration.mdx b/api_docs/cloud_data_migration.mdx index ec788541a85bb..15e2cb08a1348 100644 --- a/api_docs/cloud_data_migration.mdx +++ b/api_docs/cloud_data_migration.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDataMigration title: "cloudDataMigration" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDataMigration plugin -date: 2023-09-25 +date: 2023-09-26 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 9abc3551fb3e7..b67cc1ca1c15b 100644 --- a/api_docs/cloud_defend.mdx +++ b/api_docs/cloud_defend.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDefend title: "cloudDefend" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDefend plugin -date: 2023-09-25 +date: 2023-09-26 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 712dfc663997b..1934cb490d159 100644 --- a/api_docs/cloud_experiments.mdx +++ b/api_docs/cloud_experiments.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudExperiments title: "cloudExperiments" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudExperiments plugin -date: 2023-09-25 +date: 2023-09-26 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 05f3ba75ce256..da9f05b588386 100644 --- a/api_docs/cloud_security_posture.mdx +++ b/api_docs/cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudSecurityPosture title: "cloudSecurityPosture" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudSecurityPosture plugin -date: 2023-09-25 +date: 2023-09-26 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 10c18a585b964..4474707f4dd51 100644 --- a/api_docs/console.mdx +++ b/api_docs/console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/console title: "console" image: https://source.unsplash.com/400x175/?github description: API docs for the console plugin -date: 2023-09-25 +date: 2023-09-26 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 ed10bf00b57f4..8155448ed0693 100644 --- a/api_docs/content_management.mdx +++ b/api_docs/content_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/contentManagement title: "contentManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the contentManagement plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'contentManagement'] --- import contentManagementObj from './content_management.devdocs.json'; diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index b3f68a15ccdc9..635d1eb9d7dc1 100644 --- a/api_docs/controls.mdx +++ b/api_docs/controls.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/controls title: "controls" image: https://source.unsplash.com/400x175/?github description: API docs for the controls plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index 2bb12ec6c9fd8..1437ef65bd31f 100644 --- a/api_docs/custom_integrations.mdx +++ b/api_docs/custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/customIntegrations title: "customIntegrations" image: https://source.unsplash.com/400x175/?github description: API docs for the customIntegrations plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'customIntegrations'] --- import customIntegrationsObj from './custom_integrations.devdocs.json'; diff --git a/api_docs/dashboard.mdx b/api_docs/dashboard.mdx index 42f23759f1ed6..a4df4f9d5b629 100644 --- a/api_docs/dashboard.mdx +++ b/api_docs/dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboard title: "dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboard plugin -date: 2023-09-25 +date: 2023-09-26 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 6e42e2694b4d7..8e2207a743ba8 100644 --- a/api_docs/dashboard_enhanced.mdx +++ b/api_docs/dashboard_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboardEnhanced title: "dashboardEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboardEnhanced plugin -date: 2023-09-25 +date: 2023-09-26 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 698d91dce0dcd..556287b22aa60 100644 --- a/api_docs/data.mdx +++ b/api_docs/data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data title: "data" image: https://source.unsplash.com/400x175/?github description: API docs for the data plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index c7821d531f7c8..644aec8b976e2 100644 --- a/api_docs/data_query.mdx +++ b/api_docs/data_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-query title: "data.query" image: https://source.unsplash.com/400x175/?github description: API docs for the data.query plugin -date: 2023-09-25 +date: 2023-09-26 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 055894784f580..853e83d7d02d6 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-search title: "data.search" image: https://source.unsplash.com/400x175/?github description: API docs for the data.search plugin -date: 2023-09-25 +date: 2023-09-26 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 82418c06b69d4..10ad3cbc15742 100644 --- a/api_docs/data_view_editor.mdx +++ b/api_docs/data_view_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewEditor title: "dataViewEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewEditor plugin -date: 2023-09-25 +date: 2023-09-26 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 786031f8cc084..10c172ab937ec 100644 --- a/api_docs/data_view_field_editor.mdx +++ b/api_docs/data_view_field_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewFieldEditor title: "dataViewFieldEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewFieldEditor plugin -date: 2023-09-25 +date: 2023-09-26 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 4e36621ef1307..84cd5b94c54f4 100644 --- a/api_docs/data_view_management.mdx +++ b/api_docs/data_view_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewManagement title: "dataViewManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewManagement plugin -date: 2023-09-25 +date: 2023-09-26 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 41381b90f8595..1e0f35b08fd89 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViews title: "dataViews" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViews plugin -date: 2023-09-25 +date: 2023-09-26 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 cc4bbc5a7e8fa..03205c22a0910 100644 --- a/api_docs/data_visualizer.mdx +++ b/api_docs/data_visualizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataVisualizer title: "dataVisualizer" image: https://source.unsplash.com/400x175/?github description: API docs for the dataVisualizer plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index 6f732a8e26478..3977a95f479c1 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByApi slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-api title: Deprecated API usage by API description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -96,7 +96,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core-saved-objects-browser-internal, @kbn/core | - | | | @kbn/core-saved-objects-browser-internal, @kbn/core | - | | | @kbn/core-saved-objects-browser-internal | - | -| | home, osquery | - | | | @kbn/core-root-browser-internal, @kbn/core-saved-objects-browser-mocks | - | | | graph, visTypeTimeseries, dataViewManagement, dataViews | - | | | graph, visTypeTimeseries, dataViewManagement, dataViews | - | @@ -190,7 +189,6 @@ Safe to remove. | | expressions | | | home | | | kibanaReact | -| | kibanaReact | | | kibanaReact | | | kibanaReact | | | licensing | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 0cc43997049d1..71e6a906296dc 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByPlugin slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-plugin title: Deprecated API usage by plugin description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -965,7 +965,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | ---------------|-----------|-----------| | | [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion) | - | | | [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts#:~:text=migrationVersion)+ 30 more | - | -| | [tutorial_directory.js](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/components/tutorial_directory.js#:~:text=KibanaPageTemplate), [tutorial_directory.js](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/components/tutorial_directory.js#:~:text=KibanaPageTemplate), [tutorial_directory.js](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/components/tutorial_directory.js#:~:text=KibanaPageTemplate), [tutorial.js](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/components/tutorial/tutorial.js#:~:text=KibanaPageTemplate), [tutorial.js](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/components/tutorial/tutorial.js#:~:text=KibanaPageTemplate), [tutorial.js](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/components/tutorial/tutorial.js#:~:text=KibanaPageTemplate), [tutorial.js](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/components/tutorial/tutorial.js#:~:text=KibanaPageTemplate) | - | | | [add_data.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/components/add_data/add_data.tsx#:~:text=RedirectAppLinks), [add_data.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/components/add_data/add_data.tsx#:~:text=RedirectAppLinks), [add_data.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/components/add_data/add_data.tsx#:~:text=RedirectAppLinks), [manage_data.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/components/manage_data/manage_data.tsx#:~:text=RedirectAppLinks), [manage_data.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/components/manage_data/manage_data.tsx#:~:text=RedirectAppLinks), [manage_data.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/components/manage_data/manage_data.tsx#:~:text=RedirectAppLinks), [manage_data.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/components/manage_data/manage_data.tsx#:~:text=RedirectAppLinks), [manage_data.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/components/manage_data/manage_data.tsx#:~:text=RedirectAppLinks), [application.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/application.tsx#:~:text=RedirectAppLinks), [application.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/application.tsx#:~:text=RedirectAppLinks)+ 1 more | - | | | [application.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/application.tsx#:~:text=KibanaThemeProvider), [application.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/application.tsx#:~:text=KibanaThemeProvider), [application.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/application/application.tsx#:~:text=KibanaThemeProvider) | - | | | [plugin.ts](https://github.com/elastic/kibana/tree/main/src/plugins/home/public/plugin.ts#:~:text=savedObjects) | - | @@ -1268,7 +1267,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [read_pack_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/server/routes/pack/read_pack_route.ts#:~:text=migrationVersion) | - | | | [read_pack_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/server/routes/pack/read_pack_route.ts#:~:text=migrationVersion), [read_pack_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/server/routes/pack/read_pack_route.ts#:~:text=migrationVersion), [read_pack_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/server/routes/pack/read_pack_route.ts#:~:text=migrationVersion), [read_pack_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/server/routes/pack/read_pack_route.ts#:~:text=migrationVersion) | - | | | [pack_queries_status_table.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/public/packs/pack_queries_status_table.tsx#:~:text=indexPatternId), [view_results_in_discover.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/public/discover/view_results_in_discover.tsx#:~:text=indexPatternId), [use_discover_link.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/public/common/hooks/use_discover_link.tsx#:~:text=indexPatternId) | - | -| | [empty_state.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/public/components/empty_state.tsx#:~:text=KibanaPageTemplate), [empty_state.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/public/components/empty_state.tsx#:~:text=KibanaPageTemplate) | - | | | [osquery_result_wrapper.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_result_wrapper.tsx#:~:text=KibanaThemeProvider), [osquery_result_wrapper.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_result_wrapper.tsx#:~:text=KibanaThemeProvider), [osquery_result_wrapper.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_result_wrapper.tsx#:~:text=KibanaThemeProvider), [shared_imports.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/public/shared_imports.ts#:~:text=KibanaThemeProvider), [osquery_results.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_results.tsx#:~:text=KibanaThemeProvider), [osquery_results.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_results.tsx#:~:text=KibanaThemeProvider), [osquery_results.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_results.tsx#:~:text=KibanaThemeProvider), [services_wrapper.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/public/shared_components/services_wrapper.tsx#:~:text=KibanaThemeProvider), [services_wrapper.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/public/shared_components/services_wrapper.tsx#:~:text=KibanaThemeProvider), [services_wrapper.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/public/shared_components/services_wrapper.tsx#:~:text=KibanaThemeProvider)+ 3 more | - | | | [create_action_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/osquery/server/handlers/action/create_action_service.ts#:~:text=license%24) | 8.8.0 | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index f8a6e88eb34d3..81ecaa3b56c29 100644 --- a/api_docs/deprecations_by_team.mdx +++ b/api_docs/deprecations_by_team.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsDueByTeam slug: /kibana-dev-docs/api-meta/deprecations-due-by-team title: Deprecated APIs due to be removed, by team description: Lists the teams that are referencing deprecated APIs with a remove by date. -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index 4dc67b1161cd9..f4c8a663168f7 100644 --- a/api_docs/dev_tools.mdx +++ b/api_docs/dev_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/devTools title: "devTools" image: https://source.unsplash.com/400x175/?github description: API docs for the devTools plugin -date: 2023-09-25 +date: 2023-09-26 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 16b69231cdbe2..9470adde29441 100644 --- a/api_docs/discover.mdx +++ b/api_docs/discover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discover title: "discover" image: https://source.unsplash.com/400x175/?github description: API docs for the discover plugin -date: 2023-09-25 +date: 2023-09-26 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 3e9f3e1df6efe..ca1aa13a7a575 100644 --- a/api_docs/discover_enhanced.mdx +++ b/api_docs/discover_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverEnhanced title: "discoverEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverEnhanced plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/ecs_data_quality_dashboard.mdx b/api_docs/ecs_data_quality_dashboard.mdx index a5dc05d2871de..92763c877c9a8 100644 --- a/api_docs/ecs_data_quality_dashboard.mdx +++ b/api_docs/ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ecsDataQualityDashboard title: "ecsDataQualityDashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the ecsDataQualityDashboard plugin -date: 2023-09-25 +date: 2023-09-26 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 ed94fe83ad391..02d6d501b1700 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'elasticAssistant'] --- import elasticAssistantObj from './elastic_assistant.devdocs.json'; diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index c10cb41ea3212..78fa7d6fbef6b 100644 --- a/api_docs/embeddable.mdx +++ b/api_docs/embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddable title: "embeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddable plugin -date: 2023-09-25 +date: 2023-09-26 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 3070470e2b5a5..6b4f362298339 100644 --- a/api_docs/embeddable_enhanced.mdx +++ b/api_docs/embeddable_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddableEnhanced title: "embeddableEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddableEnhanced plugin -date: 2023-09-25 +date: 2023-09-26 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 b7d75a4c4ef33..db61a703d2915 100644 --- a/api_docs/encrypted_saved_objects.mdx +++ b/api_docs/encrypted_saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/encryptedSavedObjects title: "encryptedSavedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the encryptedSavedObjects plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'encryptedSavedObjects'] --- import encryptedSavedObjectsObj from './encrypted_saved_objects.devdocs.json'; diff --git a/api_docs/enterprise_search.devdocs.json b/api_docs/enterprise_search.devdocs.json index 318a97a2de824..aa4cff43ad780 100644 --- a/api_docs/enterprise_search.devdocs.json +++ b/api_docs/enterprise_search.devdocs.json @@ -59,21 +59,6 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false - }, - { - "parentPluginId": "enterpriseSearch", - "id": "def-server.EnterpriseSearchPluginStart", - "type": "Type", - "tags": [], - "label": "EnterpriseSearchPluginStart", - "description": [], - "signature": [ - "PluginStart" - ], - "path": "x-pack/plugins/enterprise_search/server/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false } ], "objects": [ diff --git a/api_docs/enterprise_search.mdx b/api_docs/enterprise_search.mdx index fee8429037ae7..e23ffd9c0e090 100644 --- a/api_docs/enterprise_search.mdx +++ b/api_docs/enterprise_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/enterpriseSearch title: "enterpriseSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the enterpriseSearch plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/te | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 6 | 0 | 6 | 0 | +| 5 | 0 | 5 | 0 | ## Client diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index 07b97cfb592a5..3d88e82266b09 100644 --- a/api_docs/es_ui_shared.mdx +++ b/api_docs/es_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esUiShared title: "esUiShared" image: https://source.unsplash.com/400x175/?github description: API docs for the esUiShared plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index b3d3515c4fa14..67a2fa95c3019 100644 --- a/api_docs/event_annotation.mdx +++ b/api_docs/event_annotation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotation title: "eventAnnotation" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotation plugin -date: 2023-09-25 +date: 2023-09-26 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 8839599be165d..d7f54f483495f 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: 2023-09-25 +date: 2023-09-26 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 e85389d1f437b..ca37dcdc39e72 100644 --- a/api_docs/event_log.mdx +++ b/api_docs/event_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventLog title: "eventLog" image: https://source.unsplash.com/400x175/?github description: API docs for the eventLog plugin -date: 2023-09-25 +date: 2023-09-26 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 f7b509cbfdb1b..3d41811601ad1 100644 --- a/api_docs/exploratory_view.mdx +++ b/api_docs/exploratory_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/exploratoryView title: "exploratoryView" image: https://source.unsplash.com/400x175/?github description: API docs for the exploratoryView plugin -date: 2023-09-25 +date: 2023-09-26 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 7a4cda0d34010..5ed1bbfab229c 100644 --- a/api_docs/expression_error.mdx +++ b/api_docs/expression_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionError title: "expressionError" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionError plugin -date: 2023-09-25 +date: 2023-09-26 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 49697cf849ee9..ad2dfe5486f85 100644 --- a/api_docs/expression_gauge.mdx +++ b/api_docs/expression_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionGauge title: "expressionGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionGauge plugin -date: 2023-09-25 +date: 2023-09-26 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 c808902199715..c77732e6854be 100644 --- a/api_docs/expression_heatmap.mdx +++ b/api_docs/expression_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionHeatmap title: "expressionHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionHeatmap plugin -date: 2023-09-25 +date: 2023-09-26 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 2d89902efab22..f4efc14efc855 100644 --- a/api_docs/expression_image.mdx +++ b/api_docs/expression_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionImage title: "expressionImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionImage plugin -date: 2023-09-25 +date: 2023-09-26 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 9a9bf83a54734..991a3ccc2ecfd 100644 --- a/api_docs/expression_legacy_metric_vis.mdx +++ b/api_docs/expression_legacy_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionLegacyMetricVis title: "expressionLegacyMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionLegacyMetricVis plugin -date: 2023-09-25 +date: 2023-09-26 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 4f3a80337aef0..3616b76fc9b8d 100644 --- a/api_docs/expression_metric.mdx +++ b/api_docs/expression_metric.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetric title: "expressionMetric" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetric plugin -date: 2023-09-25 +date: 2023-09-26 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 f6123702f5b80..ef0d0acf0cfa6 100644 --- a/api_docs/expression_metric_vis.mdx +++ b/api_docs/expression_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetricVis title: "expressionMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetricVis plugin -date: 2023-09-25 +date: 2023-09-26 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 fa8638f10728d..7d8b20f7423b3 100644 --- a/api_docs/expression_partition_vis.mdx +++ b/api_docs/expression_partition_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionPartitionVis title: "expressionPartitionVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionPartitionVis plugin -date: 2023-09-25 +date: 2023-09-26 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 97b46b486beb5..70d9fe0be3f65 100644 --- a/api_docs/expression_repeat_image.mdx +++ b/api_docs/expression_repeat_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRepeatImage title: "expressionRepeatImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRepeatImage plugin -date: 2023-09-25 +date: 2023-09-26 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 9521040c51bc2..f206257eb990f 100644 --- a/api_docs/expression_reveal_image.mdx +++ b/api_docs/expression_reveal_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRevealImage title: "expressionRevealImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRevealImage plugin -date: 2023-09-25 +date: 2023-09-26 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 3599dc7b2d1fb..fa40bf6fefc1b 100644 --- a/api_docs/expression_shape.mdx +++ b/api_docs/expression_shape.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionShape title: "expressionShape" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionShape plugin -date: 2023-09-25 +date: 2023-09-26 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 9392f76dd50c7..9bc625fef6886 100644 --- a/api_docs/expression_tagcloud.mdx +++ b/api_docs/expression_tagcloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionTagcloud title: "expressionTagcloud" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionTagcloud plugin -date: 2023-09-25 +date: 2023-09-26 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 86c39e2e588c3..58134a1646421 100644 --- a/api_docs/expression_x_y.mdx +++ b/api_docs/expression_x_y.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionXY title: "expressionXY" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionXY plugin -date: 2023-09-25 +date: 2023-09-26 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 351ab76914882..2beb233b9c7bd 100644 --- a/api_docs/expressions.mdx +++ b/api_docs/expressions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressions title: "expressions" image: https://source.unsplash.com/400x175/?github description: API docs for the expressions plugin -date: 2023-09-25 +date: 2023-09-26 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 4392d8382ec87..0a4a09158b8da 100644 --- a/api_docs/features.mdx +++ b/api_docs/features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/features title: "features" image: https://source.unsplash.com/400x175/?github description: API docs for the features plugin -date: 2023-09-25 +date: 2023-09-26 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 dfc37187d7e65..ba867d77d18db 100644 --- a/api_docs/field_formats.mdx +++ b/api_docs/field_formats.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldFormats title: "fieldFormats" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldFormats plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index 84d266a5cc635..7c30ad8b84139 100644 --- a/api_docs/file_upload.mdx +++ b/api_docs/file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fileUpload title: "fileUpload" image: https://source.unsplash.com/400x175/?github description: API docs for the fileUpload plugin -date: 2023-09-25 +date: 2023-09-26 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 30fbc32a97c20..8472065eba41d 100644 --- a/api_docs/files.mdx +++ b/api_docs/files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/files title: "files" image: https://source.unsplash.com/400x175/?github description: API docs for the files plugin -date: 2023-09-25 +date: 2023-09-26 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 c88197cfa5273..c29a23abef03d 100644 --- a/api_docs/files_management.mdx +++ b/api_docs/files_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/filesManagement title: "filesManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the filesManagement plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'filesManagement'] --- import filesManagementObj from './files_management.devdocs.json'; diff --git a/api_docs/fleet.devdocs.json b/api_docs/fleet.devdocs.json index cb9c82a0f53ca..05e8cfe459150 100644 --- a/api_docs/fleet.devdocs.json +++ b/api_docs/fleet.devdocs.json @@ -19712,34 +19712,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "fleet", - "id": "def-common.FullAgentPolicyOutputPermissions", - "type": "Interface", - "tags": [], - "label": "FullAgentPolicyOutputPermissions", - "description": [], - "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "fleet", - "id": "def-common.FullAgentPolicyOutputPermissions.Unnamed", - "type": "IndexSignature", - "tags": [], - "label": "[packagePolicyName: string]: { cluster?: string[] | undefined; indices?: { names: string[]; privileges: string[]; }[] | undefined; }", - "description": [], - "signature": [ - "[packagePolicyName: string]: { cluster?: string[] | undefined; indices?: { names: string[]; privileges: string[]; }[] | undefined; }" - ], - "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "fleet", "id": "def-common.GetAgentPoliciesRequest", @@ -24505,6 +24477,23 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "fleet", + "id": "def-common.FullAgentPolicyOutputPermissions", + "type": "Type", + "tags": [], + "label": "FullAgentPolicyOutputPermissions", + "description": [], + "signature": [ + "{ [x: string]: ", + "SecurityRoleDescriptor", + "; }" + ], + "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "fleet", "id": "def-common.GetAgentPoliciesResponse", diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index e35b222d2d8e3..2c2ae86b9c9d4 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fleet title: "fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the fleet plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] --- import fleetObj from './fleet.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 1201 | 3 | 1083 | 41 | +| 1200 | 3 | 1082 | 41 | ## Client diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index 1d12cd375c9e5..df980b8e1e648 100644 --- a/api_docs/global_search.mdx +++ b/api_docs/global_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/globalSearch title: "globalSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the globalSearch plugin -date: 2023-09-25 +date: 2023-09-26 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 d5b03bb5f8721..8c8db8cda054b 100644 --- a/api_docs/guided_onboarding.mdx +++ b/api_docs/guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/guidedOnboarding title: "guidedOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the guidedOnboarding plugin -date: 2023-09-25 +date: 2023-09-26 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 0d09c64282018..03efc5f145f50 100644 --- a/api_docs/home.mdx +++ b/api_docs/home.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/home title: "home" image: https://source.unsplash.com/400x175/?github description: API docs for the home plugin -date: 2023-09-25 +date: 2023-09-26 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 3c45419e1a621..d580d7279dca1 100644 --- a/api_docs/image_embeddable.mdx +++ b/api_docs/image_embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/imageEmbeddable title: "imageEmbeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the imageEmbeddable plugin -date: 2023-09-25 +date: 2023-09-26 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 ce70ab027ad8f..37ffce58d2121 100644 --- a/api_docs/index_lifecycle_management.mdx +++ b/api_docs/index_lifecycle_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexLifecycleManagement title: "indexLifecycleManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexLifecycleManagement plugin -date: 2023-09-25 +date: 2023-09-26 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 a07570c8fd12b..b9e6e34026aa3 100644 --- a/api_docs/index_management.mdx +++ b/api_docs/index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexManagement title: "indexManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexManagement plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index 7c299671369ad..537827b5f495f 100644 --- a/api_docs/infra.mdx +++ b/api_docs/infra.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/infra title: "infra" image: https://source.unsplash.com/400x175/?github description: API docs for the infra plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index 4b7e5f2909a92..f5a8d45c50692 100644 --- a/api_docs/inspector.mdx +++ b/api_docs/inspector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inspector title: "inspector" image: https://source.unsplash.com/400x175/?github description: API docs for the inspector plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index 78aee62715069..202e64cb65007 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/interactiveSetup title: "interactiveSetup" image: https://source.unsplash.com/400x175/?github description: API docs for the interactiveSetup plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index 79e1fe67e01f8..d04cba38b65e6 100644 --- a/api_docs/kbn_ace.mdx +++ b/api_docs/kbn_ace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ace title: "@kbn/ace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ace plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index a364d32cc3800..e453c0eefb68a 100644 --- a/api_docs/kbn_aiops_components.mdx +++ b/api_docs/kbn_aiops_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-components title: "@kbn/aiops-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-components plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; diff --git a/api_docs/kbn_aiops_utils.mdx b/api_docs/kbn_aiops_utils.mdx index a1843c6ed4e25..e385fd4517c2c 100644 --- a/api_docs/kbn_aiops_utils.mdx +++ b/api_docs/kbn_aiops_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-utils title: "@kbn/aiops-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-utils plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-utils'] --- import kbnAiopsUtilsObj from './kbn_aiops_utils.devdocs.json'; diff --git a/api_docs/kbn_alerting_api_integration_helpers.mdx b/api_docs/kbn_alerting_api_integration_helpers.mdx index a31f9f33a9970..42704e94f816d 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-api-integration-helpers'] --- import kbnAlertingApiIntegrationHelpersObj from './kbn_alerting_api_integration_helpers.devdocs.json'; diff --git a/api_docs/kbn_alerting_state_types.mdx b/api_docs/kbn_alerting_state_types.mdx index 10de8a7bdf4ac..e322ca58e9426 100644 --- a/api_docs/kbn_alerting_state_types.mdx +++ b/api_docs/kbn_alerting_state_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-state-types title: "@kbn/alerting-state-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-state-types plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-state-types'] --- import kbnAlertingStateTypesObj from './kbn_alerting_state_types.devdocs.json'; diff --git a/api_docs/kbn_alerts_as_data_utils.mdx b/api_docs/kbn_alerts_as_data_utils.mdx index ae626493cf59c..50486c8ad807f 100644 --- a/api_docs/kbn_alerts_as_data_utils.mdx +++ b/api_docs/kbn_alerts_as_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-as-data-utils title: "@kbn/alerts-as-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-as-data-utils plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-as-data-utils'] --- import kbnAlertsAsDataUtilsObj from './kbn_alerts_as_data_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts_ui_shared.mdx b/api_docs/kbn_alerts_ui_shared.mdx index 91f44207566ab..648f53b3d0e06 100644 --- a/api_docs/kbn_alerts_ui_shared.mdx +++ b/api_docs/kbn_alerts_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-ui-shared title: "@kbn/alerts-ui-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-ui-shared plugin -date: 2023-09-25 +date: 2023-09-26 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 d8a0804885a41..7f17d6c2e675f 100644 --- a/api_docs/kbn_analytics.mdx +++ b/api_docs/kbn_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics title: "@kbn/analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_client.mdx b/api_docs/kbn_analytics_client.mdx index c9b4b41ef5450..8dc81b42cacd3 100644 --- a/api_docs/kbn_analytics_client.mdx +++ b/api_docs/kbn_analytics_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-client title: "@kbn/analytics-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-client plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-client'] --- import kbnAnalyticsClientObj from './kbn_analytics_client.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx index b66284ebbb763..e9450ce0f465c 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-browser title: "@kbn/analytics-shippers-elastic-v3-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-browser plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-browser'] --- import kbnAnalyticsShippersElasticV3BrowserObj from './kbn_analytics_shippers_elastic_v3_browser.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx index 416721c3f0efb..1789d7c2204b8 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-common title: "@kbn/analytics-shippers-elastic-v3-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-common plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-common'] --- import kbnAnalyticsShippersElasticV3CommonObj from './kbn_analytics_shippers_elastic_v3_common.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx index 2b41be28bb0f0..944c658d43ed1 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-server title: "@kbn/analytics-shippers-elastic-v3-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-server'] --- import kbnAnalyticsShippersElasticV3ServerObj from './kbn_analytics_shippers_elastic_v3_server.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_fullstory.mdx b/api_docs/kbn_analytics_shippers_fullstory.mdx index a44f2ab06e9a8..f99f5d6067e73 100644 --- a/api_docs/kbn_analytics_shippers_fullstory.mdx +++ b/api_docs/kbn_analytics_shippers_fullstory.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-fullstory title: "@kbn/analytics-shippers-fullstory" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-fullstory plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-fullstory'] --- import kbnAnalyticsShippersFullstoryObj from './kbn_analytics_shippers_fullstory.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_gainsight.mdx b/api_docs/kbn_analytics_shippers_gainsight.mdx index 9a25aeefe7ba6..05f6b5377964c 100644 --- a/api_docs/kbn_analytics_shippers_gainsight.mdx +++ b/api_docs/kbn_analytics_shippers_gainsight.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-gainsight title: "@kbn/analytics-shippers-gainsight" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-gainsight plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-gainsight'] --- import kbnAnalyticsShippersGainsightObj from './kbn_analytics_shippers_gainsight.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index f751bcef82a7c..1df6fc7694cc6 100644 --- a/api_docs/kbn_apm_config_loader.mdx +++ b/api_docs/kbn_apm_config_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-config-loader title: "@kbn/apm-config-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-config-loader plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-config-loader'] --- import kbnApmConfigLoaderObj from './kbn_apm_config_loader.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace.mdx b/api_docs/kbn_apm_synthtrace.mdx index 14fdfd72f294e..e7655fe80551e 100644 --- a/api_docs/kbn_apm_synthtrace.mdx +++ b/api_docs/kbn_apm_synthtrace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace title: "@kbn/apm-synthtrace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace_client.mdx b/api_docs/kbn_apm_synthtrace_client.mdx index c3b594a208989..cb95b018fd98f 100644 --- a/api_docs/kbn_apm_synthtrace_client.mdx +++ b/api_docs/kbn_apm_synthtrace_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace-client title: "@kbn/apm-synthtrace-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace-client plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace-client'] --- import kbnApmSynthtraceClientObj from './kbn_apm_synthtrace_client.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index 9a5ce9ccd6e8d..8f3fb9d5b7ed2 100644 --- a/api_docs/kbn_apm_utils.mdx +++ b/api_docs/kbn_apm_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-utils title: "@kbn/apm-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-utils plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index efec62cb7205c..cd10d689c2b4e 100644 --- a/api_docs/kbn_axe_config.mdx +++ b/api_docs/kbn_axe_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-axe-config title: "@kbn/axe-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/axe-config plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_cases_components.mdx b/api_docs/kbn_cases_components.mdx index 50d478a423436..1431068c738ec 100644 --- a/api_docs/kbn_cases_components.mdx +++ b/api_docs/kbn_cases_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cases-components title: "@kbn/cases-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cases-components plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cases-components'] --- import kbnCasesComponentsObj from './kbn_cases_components.devdocs.json'; diff --git a/api_docs/kbn_cell_actions.mdx b/api_docs/kbn_cell_actions.mdx index fe977a8118a46..203243d1243ef 100644 --- a/api_docs/kbn_cell_actions.mdx +++ b/api_docs/kbn_cell_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cell-actions title: "@kbn/cell-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cell-actions plugin -date: 2023-09-25 +date: 2023-09-26 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 fa7bfde0894e4..10fc0677fd070 100644 --- a/api_docs/kbn_chart_expressions_common.mdx +++ b/api_docs/kbn_chart_expressions_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-expressions-common title: "@kbn/chart-expressions-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-expressions-common plugin -date: 2023-09-25 +date: 2023-09-26 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 5b42c177beaa4..9b3b38d498a71 100644 --- a/api_docs/kbn_chart_icons.mdx +++ b/api_docs/kbn_chart_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-icons title: "@kbn/chart-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-icons plugin -date: 2023-09-25 +date: 2023-09-26 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 f3849f529fece..29e1f6b487ed4 100644 --- a/api_docs/kbn_ci_stats_core.mdx +++ b/api_docs/kbn_ci_stats_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-core title: "@kbn/ci-stats-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-core plugin -date: 2023-09-25 +date: 2023-09-26 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 a0b8042ff4f07..516cb6f154c35 100644 --- a/api_docs/kbn_ci_stats_performance_metrics.mdx +++ b/api_docs/kbn_ci_stats_performance_metrics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-performance-metrics title: "@kbn/ci-stats-performance-metrics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-performance-metrics plugin -date: 2023-09-25 +date: 2023-09-26 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 0df628917ce8e..5e4b65df6617b 100644 --- a/api_docs/kbn_ci_stats_reporter.mdx +++ b/api_docs/kbn_ci_stats_reporter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-reporter title: "@kbn/ci-stats-reporter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-reporter plugin -date: 2023-09-25 +date: 2023-09-26 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 a070f6f8921b1..7ea9623fbede0 100644 --- a/api_docs/kbn_cli_dev_mode.mdx +++ b/api_docs/kbn_cli_dev_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cli-dev-mode title: "@kbn/cli-dev-mode" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cli-dev-mode plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_code_editor.mdx b/api_docs/kbn_code_editor.mdx index e8e57d5fe77b4..6568dcfb4ebfb 100644 --- a/api_docs/kbn_code_editor.mdx +++ b/api_docs/kbn_code_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor title: "@kbn/code-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor'] --- import kbnCodeEditorObj from './kbn_code_editor.devdocs.json'; diff --git a/api_docs/kbn_code_editor_mocks.mdx b/api_docs/kbn_code_editor_mocks.mdx index 1a3923308f23f..13934919915a6 100644 --- a/api_docs/kbn_code_editor_mocks.mdx +++ b/api_docs/kbn_code_editor_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor-mocks title: "@kbn/code-editor-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor-mocks'] --- import kbnCodeEditorMocksObj from './kbn_code_editor_mocks.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index 2a93b76d2f81d..81c1e78cdb4ed 100644 --- a/api_docs/kbn_coloring.mdx +++ b/api_docs/kbn_coloring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-coloring title: "@kbn/coloring" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/coloring plugin -date: 2023-09-25 +date: 2023-09-26 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 706ddccf20a29..923d802e14cf3 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config title: "@kbn/config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config plugin -date: 2023-09-25 +date: 2023-09-26 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 eaad62dd612a4..892bb885b03e3 100644 --- a/api_docs/kbn_config_mocks.mdx +++ b/api_docs/kbn_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-mocks title: "@kbn/config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 4bee4fb17dc9b..7f75356ee1249 100644 --- a/api_docs/kbn_config_schema.mdx +++ b/api_docs/kbn_config_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-schema title: "@kbn/config-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-schema plugin -date: 2023-09-25 +date: 2023-09-26 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 e1c6270141d4a..fbdfdaa40559a 100644 --- a/api_docs/kbn_content_management_content_editor.mdx +++ b/api_docs/kbn_content_management_content_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-editor title: "@kbn/content-management-content-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-editor plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-editor'] --- import kbnContentManagementContentEditorObj from './kbn_content_management_content_editor.devdocs.json'; diff --git a/api_docs/kbn_content_management_tabbed_table_list_view.mdx b/api_docs/kbn_content_management_tabbed_table_list_view.mdx index 85b3f938ed466..b6197f9bb8f6d 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: 2023-09-25 +date: 2023-09-26 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 8ba6e130f8559..ec7f4781572a2 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: 2023-09-25 +date: 2023-09-26 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_table.mdx b/api_docs/kbn_content_management_table_list_view_table.mdx index b132504f9ba9f..1961fd018bf23 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-table'] --- import kbnContentManagementTableListViewTableObj from './kbn_content_management_table_list_view_table.devdocs.json'; diff --git a/api_docs/kbn_content_management_utils.mdx b/api_docs/kbn_content_management_utils.mdx index 4a0865321d666..ea1ddac1acccb 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: 2023-09-25 +date: 2023-09-26 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 486d9e6d99eec..556d8f62a9e15 100644 --- a/api_docs/kbn_core_analytics_browser.mdx +++ b/api_docs/kbn_core_analytics_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser title: "@kbn/core-analytics-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser plugin -date: 2023-09-25 +date: 2023-09-26 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 ab8479c1a2a60..6d148521ea8d1 100644 --- a/api_docs/kbn_core_analytics_browser_internal.mdx +++ b/api_docs/kbn_core_analytics_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-internal title: "@kbn/core-analytics-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-internal plugin -date: 2023-09-25 +date: 2023-09-26 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 6274a9e8285ad..cc3dd8e056844 100644 --- a/api_docs/kbn_core_analytics_browser_mocks.mdx +++ b/api_docs/kbn_core_analytics_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-mocks title: "@kbn/core-analytics-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 9f7d8792e7ccb..b07a9786502f7 100644 --- a/api_docs/kbn_core_analytics_server.mdx +++ b/api_docs/kbn_core_analytics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server title: "@kbn/core-analytics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server plugin -date: 2023-09-25 +date: 2023-09-26 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 032c2e0446aed..5fea29f4e0e1d 100644 --- a/api_docs/kbn_core_analytics_server_internal.mdx +++ b/api_docs/kbn_core_analytics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-internal title: "@kbn/core-analytics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 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 3f62edcfc8116..7c82f557d2a87 100644 --- a/api_docs/kbn_core_analytics_server_mocks.mdx +++ b/api_docs/kbn_core_analytics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-mocks title: "@kbn/core-analytics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 377133ce35c6f..312d72590a91d 100644 --- a/api_docs/kbn_core_application_browser.mdx +++ b/api_docs/kbn_core_application_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser title: "@kbn/core-application-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser plugin -date: 2023-09-25 +date: 2023-09-26 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 ee7455c60ea49..a59ca46e539c7 100644 --- a/api_docs/kbn_core_application_browser_internal.mdx +++ b/api_docs/kbn_core_application_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-internal title: "@kbn/core-application-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-internal plugin -date: 2023-09-25 +date: 2023-09-26 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 75d7a269942cd..cf1cc04345fd3 100644 --- a/api_docs/kbn_core_application_browser_mocks.mdx +++ b/api_docs/kbn_core_application_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-mocks title: "@kbn/core-application-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 02644f0ea4446..c29a0840b354e 100644 --- a/api_docs/kbn_core_application_common.mdx +++ b/api_docs/kbn_core_application_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-common title: "@kbn/core-application-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-common plugin -date: 2023-09-25 +date: 2023-09-26 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 98b55347ce49c..e2049a9a65f2e 100644 --- a/api_docs/kbn_core_apps_browser_internal.mdx +++ b/api_docs/kbn_core_apps_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-internal title: "@kbn/core-apps-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-internal plugin -date: 2023-09-25 +date: 2023-09-26 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 ad97bce342d85..5bac2e0c37f33 100644 --- a/api_docs/kbn_core_apps_browser_mocks.mdx +++ b/api_docs/kbn_core_apps_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-mocks title: "@kbn/core-apps-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 e31ec24b7ee60..43d3f144856b9 100644 --- a/api_docs/kbn_core_apps_server_internal.mdx +++ b/api_docs/kbn_core_apps_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-server-internal title: "@kbn/core-apps-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 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 266447aca5bcb..8b9af9a5144a5 100644 --- a/api_docs/kbn_core_base_browser_mocks.mdx +++ b/api_docs/kbn_core_base_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-browser-mocks title: "@kbn/core-base-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 0de5243285882..7c01dd0d69165 100644 --- a/api_docs/kbn_core_base_common.mdx +++ b/api_docs/kbn_core_base_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-common title: "@kbn/core-base-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-common plugin -date: 2023-09-25 +date: 2023-09-26 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 d54c8fd1e5010..478da40a47462 100644 --- a/api_docs/kbn_core_base_server_internal.mdx +++ b/api_docs/kbn_core_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-internal title: "@kbn/core-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 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 294552a92380e..15194a6f8e001 100644 --- a/api_docs/kbn_core_base_server_mocks.mdx +++ b/api_docs/kbn_core_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-mocks title: "@kbn/core-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 8b1a9a6db7717..30ee4c3ab88e0 100644 --- a/api_docs/kbn_core_capabilities_browser_mocks.mdx +++ b/api_docs/kbn_core_capabilities_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-browser-mocks title: "@kbn/core-capabilities-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 dc35497bcb73c..188e1264b1550 100644 --- a/api_docs/kbn_core_capabilities_common.mdx +++ b/api_docs/kbn_core_capabilities_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-common title: "@kbn/core-capabilities-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-common plugin -date: 2023-09-25 +date: 2023-09-26 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 d76a2e1196828..c29fe430ddf70 100644 --- a/api_docs/kbn_core_capabilities_server.mdx +++ b/api_docs/kbn_core_capabilities_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server title: "@kbn/core-capabilities-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server plugin -date: 2023-09-25 +date: 2023-09-26 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 c962351f98150..c59f5ee00abc1 100644 --- a/api_docs/kbn_core_capabilities_server_mocks.mdx +++ b/api_docs/kbn_core_capabilities_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server-mocks title: "@kbn/core-capabilities-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 b82a56c1c1d1c..c51888c62a08a 100644 --- a/api_docs/kbn_core_chrome_browser.mdx +++ b/api_docs/kbn_core_chrome_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser title: "@kbn/core-chrome-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser plugin -date: 2023-09-25 +date: 2023-09-26 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 df98400bcd696..0397d0752b446 100644 --- a/api_docs/kbn_core_chrome_browser_mocks.mdx +++ b/api_docs/kbn_core_chrome_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser-mocks title: "@kbn/core-chrome-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 e64865579bf94..a50657c6e38b3 100644 --- a/api_docs/kbn_core_config_server_internal.mdx +++ b/api_docs/kbn_core_config_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-config-server-internal title: "@kbn/core-config-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-config-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 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 9c21384cbfa5f..5d8c66c15b68f 100644 --- a/api_docs/kbn_core_custom_branding_browser.mdx +++ b/api_docs/kbn_core_custom_branding_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser title: "@kbn/core-custom-branding-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser plugin -date: 2023-09-25 +date: 2023-09-26 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 a56d1bb448b98..cd5e0c9b6441c 100644 --- a/api_docs/kbn_core_custom_branding_browser_internal.mdx +++ b/api_docs/kbn_core_custom_branding_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-internal title: "@kbn/core-custom-branding-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-internal plugin -date: 2023-09-25 +date: 2023-09-26 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 ade289f45cd62..e16a6ab16a3e6 100644 --- a/api_docs/kbn_core_custom_branding_browser_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-mocks title: "@kbn/core-custom-branding-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 a4efab50b7a76..d481eadb89a3a 100644 --- a/api_docs/kbn_core_custom_branding_common.mdx +++ b/api_docs/kbn_core_custom_branding_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-common title: "@kbn/core-custom-branding-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-common plugin -date: 2023-09-25 +date: 2023-09-26 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 6e052f7ad9df1..92f2d33e83085 100644 --- a/api_docs/kbn_core_custom_branding_server.mdx +++ b/api_docs/kbn_core_custom_branding_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server title: "@kbn/core-custom-branding-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server plugin -date: 2023-09-25 +date: 2023-09-26 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 7db1e51e24376..4ceec404db480 100644 --- a/api_docs/kbn_core_custom_branding_server_internal.mdx +++ b/api_docs/kbn_core_custom_branding_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-internal title: "@kbn/core-custom-branding-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 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 6941ae8a18d2d..386c20d007458 100644 --- a/api_docs/kbn_core_custom_branding_server_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-mocks title: "@kbn/core-custom-branding-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 ad46ffe5d8ca9..8b13822bbdb7e 100644 --- a/api_docs/kbn_core_deprecations_browser.mdx +++ b/api_docs/kbn_core_deprecations_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser title: "@kbn/core-deprecations-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser plugin -date: 2023-09-25 +date: 2023-09-26 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 fda5530322e16..b21cb7e2b2e64 100644 --- a/api_docs/kbn_core_deprecations_browser_internal.mdx +++ b/api_docs/kbn_core_deprecations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-internal title: "@kbn/core-deprecations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-internal plugin -date: 2023-09-25 +date: 2023-09-26 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 7c32329e582ce..bc244a60c7b76 100644 --- a/api_docs/kbn_core_deprecations_browser_mocks.mdx +++ b/api_docs/kbn_core_deprecations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-mocks title: "@kbn/core-deprecations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 1e5a19b76e7ea..c8d25f2ac6a48 100644 --- a/api_docs/kbn_core_deprecations_common.mdx +++ b/api_docs/kbn_core_deprecations_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-common title: "@kbn/core-deprecations-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-common plugin -date: 2023-09-25 +date: 2023-09-26 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 b6af67c9a3b40..5aea0dcc2c8ea 100644 --- a/api_docs/kbn_core_deprecations_server.mdx +++ b/api_docs/kbn_core_deprecations_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server title: "@kbn/core-deprecations-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server plugin -date: 2023-09-25 +date: 2023-09-26 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 49af6cacfa340..b398cd35681fa 100644 --- a/api_docs/kbn_core_deprecations_server_internal.mdx +++ b/api_docs/kbn_core_deprecations_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-internal title: "@kbn/core-deprecations-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 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 57071cac0ad33..a95ec4902fe1e 100644 --- a/api_docs/kbn_core_deprecations_server_mocks.mdx +++ b/api_docs/kbn_core_deprecations_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-mocks title: "@kbn/core-deprecations-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 686a273e1f787..62f1a86399f76 100644 --- a/api_docs/kbn_core_doc_links_browser.mdx +++ b/api_docs/kbn_core_doc_links_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser title: "@kbn/core-doc-links-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser plugin -date: 2023-09-25 +date: 2023-09-26 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 a304f961f707a..e45675783de06 100644 --- a/api_docs/kbn_core_doc_links_browser_mocks.mdx +++ b/api_docs/kbn_core_doc_links_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser-mocks title: "@kbn/core-doc-links-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 2c33c538d6e8e..9e6579bb6e920 100644 --- a/api_docs/kbn_core_doc_links_server.mdx +++ b/api_docs/kbn_core_doc_links_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server title: "@kbn/core-doc-links-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server plugin -date: 2023-09-25 +date: 2023-09-26 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 6acf6c5b575d3..ab219e38cb272 100644 --- a/api_docs/kbn_core_doc_links_server_mocks.mdx +++ b/api_docs/kbn_core_doc_links_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server-mocks title: "@kbn/core-doc-links-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 f9144e0549052..55e1290c8aaff 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-internal title: "@kbn/core-elasticsearch-client-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 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 37fc49d00721d..e4b22cfe3cff8 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-mocks title: "@kbn/core-elasticsearch-client-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-mocks'] --- import kbnCoreElasticsearchClientServerMocksObj from './kbn_core_elasticsearch_client_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index d090edfd00361..70e9af49d4432 100644 --- a/api_docs/kbn_core_elasticsearch_server.mdx +++ b/api_docs/kbn_core_elasticsearch_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server title: "@kbn/core-elasticsearch-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server'] --- import kbnCoreElasticsearchServerObj from './kbn_core_elasticsearch_server.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_internal.mdx b/api_docs/kbn_core_elasticsearch_server_internal.mdx index 71272c7cef588..12da90107a28b 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-internal title: "@kbn/core-elasticsearch-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-internal'] --- import kbnCoreElasticsearchServerInternalObj from './kbn_core_elasticsearch_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_server_mocks.mdx index 98905a17bb508..3ffa742445af2 100644 --- a/api_docs/kbn_core_elasticsearch_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-mocks title: "@kbn/core-elasticsearch-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-mocks'] --- import kbnCoreElasticsearchServerMocksObj from './kbn_core_elasticsearch_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_internal.mdx b/api_docs/kbn_core_environment_server_internal.mdx index f57fab3b88935..c157f6abb8cdf 100644 --- a/api_docs/kbn_core_environment_server_internal.mdx +++ b/api_docs/kbn_core_environment_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-internal title: "@kbn/core-environment-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-internal'] --- import kbnCoreEnvironmentServerInternalObj from './kbn_core_environment_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_mocks.mdx b/api_docs/kbn_core_environment_server_mocks.mdx index 2a99bab6c37e0..b518d18415957 100644 --- a/api_docs/kbn_core_environment_server_mocks.mdx +++ b/api_docs/kbn_core_environment_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-mocks title: "@kbn/core-environment-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-mocks'] --- import kbnCoreEnvironmentServerMocksObj from './kbn_core_environment_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser.mdx b/api_docs/kbn_core_execution_context_browser.mdx index ca01eb8645aa8..329e48bf6c67f 100644 --- a/api_docs/kbn_core_execution_context_browser.mdx +++ b/api_docs/kbn_core_execution_context_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser title: "@kbn/core-execution-context-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser'] --- import kbnCoreExecutionContextBrowserObj from './kbn_core_execution_context_browser.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_internal.mdx b/api_docs/kbn_core_execution_context_browser_internal.mdx index 6257f0c5de560..5a59259a19c5f 100644 --- a/api_docs/kbn_core_execution_context_browser_internal.mdx +++ b/api_docs/kbn_core_execution_context_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-internal title: "@kbn/core-execution-context-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-internal'] --- import kbnCoreExecutionContextBrowserInternalObj from './kbn_core_execution_context_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_mocks.mdx b/api_docs/kbn_core_execution_context_browser_mocks.mdx index acf845139f07a..010a58f8d3182 100644 --- a/api_docs/kbn_core_execution_context_browser_mocks.mdx +++ b/api_docs/kbn_core_execution_context_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-mocks title: "@kbn/core-execution-context-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-mocks'] --- import kbnCoreExecutionContextBrowserMocksObj from './kbn_core_execution_context_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_common.mdx b/api_docs/kbn_core_execution_context_common.mdx index 7fc0a0c12bd37..726886a22b67d 100644 --- a/api_docs/kbn_core_execution_context_common.mdx +++ b/api_docs/kbn_core_execution_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-common title: "@kbn/core-execution-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-common plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-common'] --- import kbnCoreExecutionContextCommonObj from './kbn_core_execution_context_common.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server.mdx b/api_docs/kbn_core_execution_context_server.mdx index 432db02afad4c..e28c4a5234f62 100644 --- a/api_docs/kbn_core_execution_context_server.mdx +++ b/api_docs/kbn_core_execution_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server title: "@kbn/core-execution-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server'] --- import kbnCoreExecutionContextServerObj from './kbn_core_execution_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_internal.mdx b/api_docs/kbn_core_execution_context_server_internal.mdx index 3f8f1196feac5..20731a0e92ae2 100644 --- a/api_docs/kbn_core_execution_context_server_internal.mdx +++ b/api_docs/kbn_core_execution_context_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-internal title: "@kbn/core-execution-context-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-internal'] --- import kbnCoreExecutionContextServerInternalObj from './kbn_core_execution_context_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_mocks.mdx b/api_docs/kbn_core_execution_context_server_mocks.mdx index 248c8e9e241bd..fc51d7010efea 100644 --- a/api_docs/kbn_core_execution_context_server_mocks.mdx +++ b/api_docs/kbn_core_execution_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-mocks title: "@kbn/core-execution-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-mocks'] --- import kbnCoreExecutionContextServerMocksObj from './kbn_core_execution_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser.mdx b/api_docs/kbn_core_fatal_errors_browser.mdx index 9d42d519931e0..ce04788d2cb9b 100644 --- a/api_docs/kbn_core_fatal_errors_browser.mdx +++ b/api_docs/kbn_core_fatal_errors_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser title: "@kbn/core-fatal-errors-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser'] --- import kbnCoreFatalErrorsBrowserObj from './kbn_core_fatal_errors_browser.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx index fb856e2fed194..53269aa7bb8f1 100644 --- a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx +++ b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser-mocks title: "@kbn/core-fatal-errors-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser-mocks'] --- import kbnCoreFatalErrorsBrowserMocksObj from './kbn_core_fatal_errors_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser.mdx b/api_docs/kbn_core_http_browser.mdx index 4238bb71c5699..a728eb94d98bb 100644 --- a/api_docs/kbn_core_http_browser.mdx +++ b/api_docs/kbn_core_http_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser title: "@kbn/core-http-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser'] --- import kbnCoreHttpBrowserObj from './kbn_core_http_browser.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_internal.mdx b/api_docs/kbn_core_http_browser_internal.mdx index 3cf77226174c9..9d505dced37d1 100644 --- a/api_docs/kbn_core_http_browser_internal.mdx +++ b/api_docs/kbn_core_http_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-internal title: "@kbn/core-http-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-internal'] --- import kbnCoreHttpBrowserInternalObj from './kbn_core_http_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_mocks.mdx b/api_docs/kbn_core_http_browser_mocks.mdx index 5be59f3492e0a..fba13f8a6b625 100644 --- a/api_docs/kbn_core_http_browser_mocks.mdx +++ b/api_docs/kbn_core_http_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-mocks title: "@kbn/core-http-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-mocks'] --- import kbnCoreHttpBrowserMocksObj from './kbn_core_http_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_common.mdx b/api_docs/kbn_core_http_common.mdx index d38193be3ad91..8df1fc093ea8c 100644 --- a/api_docs/kbn_core_http_common.mdx +++ b/api_docs/kbn_core_http_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-common title: "@kbn/core-http-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-common plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-common'] --- import kbnCoreHttpCommonObj from './kbn_core_http_common.devdocs.json'; diff --git a/api_docs/kbn_core_http_context_server_mocks.mdx b/api_docs/kbn_core_http_context_server_mocks.mdx index f141e8844bc45..4b39d024f5f5f 100644 --- a/api_docs/kbn_core_http_context_server_mocks.mdx +++ b/api_docs/kbn_core_http_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-context-server-mocks title: "@kbn/core-http-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-context-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-context-server-mocks'] --- import kbnCoreHttpContextServerMocksObj from './kbn_core_http_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_request_handler_context_server.mdx b/api_docs/kbn_core_http_request_handler_context_server.mdx index 5cc5834d042e9..f2b5b9831a416 100644 --- a/api_docs/kbn_core_http_request_handler_context_server.mdx +++ b/api_docs/kbn_core_http_request_handler_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-request-handler-context-server title: "@kbn/core-http-request-handler-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-request-handler-context-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-request-handler-context-server'] --- import kbnCoreHttpRequestHandlerContextServerObj from './kbn_core_http_request_handler_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server.mdx b/api_docs/kbn_core_http_resources_server.mdx index 5361d335a0d48..8b11a57de5e2a 100644 --- a/api_docs/kbn_core_http_resources_server.mdx +++ b/api_docs/kbn_core_http_resources_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server title: "@kbn/core-http-resources-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server'] --- import kbnCoreHttpResourcesServerObj from './kbn_core_http_resources_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_internal.mdx b/api_docs/kbn_core_http_resources_server_internal.mdx index 922ec51d160fa..21a50d0c8c885 100644 --- a/api_docs/kbn_core_http_resources_server_internal.mdx +++ b/api_docs/kbn_core_http_resources_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-internal title: "@kbn/core-http-resources-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-internal'] --- import kbnCoreHttpResourcesServerInternalObj from './kbn_core_http_resources_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_mocks.mdx b/api_docs/kbn_core_http_resources_server_mocks.mdx index 6f2f000aebaf3..e5f89cb8a7c5b 100644 --- a/api_docs/kbn_core_http_resources_server_mocks.mdx +++ b/api_docs/kbn_core_http_resources_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-mocks title: "@kbn/core-http-resources-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-mocks'] --- import kbnCoreHttpResourcesServerMocksObj from './kbn_core_http_resources_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_internal.mdx b/api_docs/kbn_core_http_router_server_internal.mdx index 7ca20544ec70a..7d3812b5e8ba7 100644 --- a/api_docs/kbn_core_http_router_server_internal.mdx +++ b/api_docs/kbn_core_http_router_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-internal title: "@kbn/core-http-router-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-internal'] --- import kbnCoreHttpRouterServerInternalObj from './kbn_core_http_router_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_mocks.mdx b/api_docs/kbn_core_http_router_server_mocks.mdx index 6075f982b6c3b..c71280ba59305 100644 --- a/api_docs/kbn_core_http_router_server_mocks.mdx +++ b/api_docs/kbn_core_http_router_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-mocks title: "@kbn/core-http-router-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-mocks'] --- import kbnCoreHttpRouterServerMocksObj from './kbn_core_http_router_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_server.devdocs.json b/api_docs/kbn_core_http_server.devdocs.json index e4f18b21704c9..904971793ae04 100644 --- a/api_docs/kbn_core_http_server.devdocs.json +++ b/api_docs/kbn_core_http_server.devdocs.json @@ -13113,6 +13113,14 @@ "plugin": "ml", "path": "x-pack/plugins/ml/server/routes/trained_models.ts" }, + { + "plugin": "ml", + "path": "x-pack/plugins/ml/server/routes/trained_models.ts" + }, + { + "plugin": "ml", + "path": "x-pack/plugins/ml/server/routes/trained_models.ts" + }, { "plugin": "ml", "path": "x-pack/plugins/ml/server/routes/data_frame_analytics.ts" diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index 970253280553e..7a4c2393c5718 100644 --- a/api_docs/kbn_core_http_server.mdx +++ b/api_docs/kbn_core_http_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server title: "@kbn/core-http-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index d30311b04fce5..50c42a9c5cf35 100644 --- a/api_docs/kbn_core_http_server_internal.mdx +++ b/api_docs/kbn_core_http_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-internal title: "@kbn/core-http-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-internal'] --- import kbnCoreHttpServerInternalObj from './kbn_core_http_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_mocks.mdx b/api_docs/kbn_core_http_server_mocks.mdx index 168d2225d9d73..3cc4f242d7e11 100644 --- a/api_docs/kbn_core_http_server_mocks.mdx +++ b/api_docs/kbn_core_http_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-mocks title: "@kbn/core-http-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-mocks'] --- import kbnCoreHttpServerMocksObj from './kbn_core_http_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser.mdx b/api_docs/kbn_core_i18n_browser.mdx index 17fe4418b4669..2209c106c63a8 100644 --- a/api_docs/kbn_core_i18n_browser.mdx +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser title: "@kbn/core-i18n-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser'] --- import kbnCoreI18nBrowserObj from './kbn_core_i18n_browser.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser_mocks.mdx b/api_docs/kbn_core_i18n_browser_mocks.mdx index a256d9364bfd1..56b8936b3f716 100644 --- a/api_docs/kbn_core_i18n_browser_mocks.mdx +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks title: "@kbn/core-i18n-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser-mocks'] --- import kbnCoreI18nBrowserMocksObj from './kbn_core_i18n_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server.mdx b/api_docs/kbn_core_i18n_server.mdx index 24a2af7d26e82..838f8ff2263f6 100644 --- a/api_docs/kbn_core_i18n_server.mdx +++ b/api_docs/kbn_core_i18n_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server title: "@kbn/core-i18n-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server'] --- import kbnCoreI18nServerObj from './kbn_core_i18n_server.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_internal.mdx b/api_docs/kbn_core_i18n_server_internal.mdx index f006a6af78758..0cc05510a1ffa 100644 --- a/api_docs/kbn_core_i18n_server_internal.mdx +++ b/api_docs/kbn_core_i18n_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-internal title: "@kbn/core-i18n-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-internal'] --- import kbnCoreI18nServerInternalObj from './kbn_core_i18n_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_mocks.mdx b/api_docs/kbn_core_i18n_server_mocks.mdx index c392208b437e8..f9a71a2b62db9 100644 --- a/api_docs/kbn_core_i18n_server_mocks.mdx +++ b/api_docs/kbn_core_i18n_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-mocks title: "@kbn/core-i18n-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-mocks'] --- import kbnCoreI18nServerMocksObj from './kbn_core_i18n_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index e4390d3797787..b0e3c5ba93dee 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser-mocks title: "@kbn/core-injected-metadata-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser-mocks'] --- import kbnCoreInjectedMetadataBrowserMocksObj from './kbn_core_injected_metadata_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_internal.mdx b/api_docs/kbn_core_integrations_browser_internal.mdx index 317e84fb8c929..3051546888669 100644 --- a/api_docs/kbn_core_integrations_browser_internal.mdx +++ b/api_docs/kbn_core_integrations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-internal title: "@kbn/core-integrations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-internal'] --- import kbnCoreIntegrationsBrowserInternalObj from './kbn_core_integrations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_mocks.mdx b/api_docs/kbn_core_integrations_browser_mocks.mdx index eade3cf39f004..7e7161430198b 100644 --- a/api_docs/kbn_core_integrations_browser_mocks.mdx +++ b/api_docs/kbn_core_integrations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-mocks title: "@kbn/core-integrations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-mocks'] --- import kbnCoreIntegrationsBrowserMocksObj from './kbn_core_integrations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser.mdx b/api_docs/kbn_core_lifecycle_browser.mdx index f07790eff7083..5b15ca47b8ba0 100644 --- a/api_docs/kbn_core_lifecycle_browser.mdx +++ b/api_docs/kbn_core_lifecycle_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser title: "@kbn/core-lifecycle-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser'] --- import kbnCoreLifecycleBrowserObj from './kbn_core_lifecycle_browser.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser_mocks.mdx b/api_docs/kbn_core_lifecycle_browser_mocks.mdx index 737749f292e5c..0a0b09c8badd2 100644 --- a/api_docs/kbn_core_lifecycle_browser_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser-mocks title: "@kbn/core-lifecycle-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser-mocks'] --- import kbnCoreLifecycleBrowserMocksObj from './kbn_core_lifecycle_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server.mdx b/api_docs/kbn_core_lifecycle_server.mdx index 713685bcd1482..e94a160c1fc75 100644 --- a/api_docs/kbn_core_lifecycle_server.mdx +++ b/api_docs/kbn_core_lifecycle_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server title: "@kbn/core-lifecycle-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server'] --- import kbnCoreLifecycleServerObj from './kbn_core_lifecycle_server.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server_mocks.mdx b/api_docs/kbn_core_lifecycle_server_mocks.mdx index 245e26d3806c9..910e75060fc09 100644 --- a/api_docs/kbn_core_lifecycle_server_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server-mocks title: "@kbn/core-lifecycle-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server-mocks'] --- import kbnCoreLifecycleServerMocksObj from './kbn_core_lifecycle_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_browser_mocks.mdx b/api_docs/kbn_core_logging_browser_mocks.mdx index bc624a5d19ab4..5523472f15956 100644 --- a/api_docs/kbn_core_logging_browser_mocks.mdx +++ b/api_docs/kbn_core_logging_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-browser-mocks title: "@kbn/core-logging-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-browser-mocks'] --- import kbnCoreLoggingBrowserMocksObj from './kbn_core_logging_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_common_internal.mdx b/api_docs/kbn_core_logging_common_internal.mdx index 768901164de5d..cef0f65f3a6fd 100644 --- a/api_docs/kbn_core_logging_common_internal.mdx +++ b/api_docs/kbn_core_logging_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-common-internal title: "@kbn/core-logging-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-common-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-common-internal'] --- import kbnCoreLoggingCommonInternalObj from './kbn_core_logging_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index 8f22ed3890ae0..da9b23df4180d 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server'] --- import kbnCoreLoggingServerObj from './kbn_core_logging_server.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_internal.mdx b/api_docs/kbn_core_logging_server_internal.mdx index 19b7dacd488ca..19294db4223bd 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-internal'] --- import kbnCoreLoggingServerInternalObj from './kbn_core_logging_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_mocks.mdx b/api_docs/kbn_core_logging_server_mocks.mdx index 636caf98f68a0..053a7eabc85bc 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-mocks'] --- import kbnCoreLoggingServerMocksObj from './kbn_core_logging_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_internal.mdx b/api_docs/kbn_core_metrics_collectors_server_internal.mdx index 977b6d8a719d2..518f82123b971 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-internal title: "@kbn/core-metrics-collectors-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-internal'] --- import kbnCoreMetricsCollectorsServerInternalObj from './kbn_core_metrics_collectors_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx index deb572120287b..b122c49584404 100644 --- a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-mocks title: "@kbn/core-metrics-collectors-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-mocks'] --- import kbnCoreMetricsCollectorsServerMocksObj from './kbn_core_metrics_collectors_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server.mdx b/api_docs/kbn_core_metrics_server.mdx index d88ff2994d574..766cd857349d8 100644 --- a/api_docs/kbn_core_metrics_server.mdx +++ b/api_docs/kbn_core_metrics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server title: "@kbn/core-metrics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server'] --- import kbnCoreMetricsServerObj from './kbn_core_metrics_server.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_internal.mdx b/api_docs/kbn_core_metrics_server_internal.mdx index e528c599dc84f..7cc522ab4fd71 100644 --- a/api_docs/kbn_core_metrics_server_internal.mdx +++ b/api_docs/kbn_core_metrics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-internal title: "@kbn/core-metrics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-internal'] --- import kbnCoreMetricsServerInternalObj from './kbn_core_metrics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_mocks.mdx b/api_docs/kbn_core_metrics_server_mocks.mdx index 25beb062d5c04..4393db1b67188 100644 --- a/api_docs/kbn_core_metrics_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-mocks title: "@kbn/core-metrics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-mocks'] --- import kbnCoreMetricsServerMocksObj from './kbn_core_metrics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser.mdx b/api_docs/kbn_core_mount_utils_browser.mdx index 84fbdd2cfcb6e..6ff8192a33ffb 100644 --- a/api_docs/kbn_core_mount_utils_browser.mdx +++ b/api_docs/kbn_core_mount_utils_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser title: "@kbn/core-mount-utils-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser'] --- import kbnCoreMountUtilsBrowserObj from './kbn_core_mount_utils_browser.devdocs.json'; diff --git a/api_docs/kbn_core_node_server.mdx b/api_docs/kbn_core_node_server.mdx index a35be2195ebd1..48ed61324dcea 100644 --- a/api_docs/kbn_core_node_server.mdx +++ b/api_docs/kbn_core_node_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server title: "@kbn/core-node-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server'] --- import kbnCoreNodeServerObj from './kbn_core_node_server.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_internal.mdx b/api_docs/kbn_core_node_server_internal.mdx index e62f569fb9778..c6b0583a49400 100644 --- a/api_docs/kbn_core_node_server_internal.mdx +++ b/api_docs/kbn_core_node_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-internal title: "@kbn/core-node-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-internal'] --- import kbnCoreNodeServerInternalObj from './kbn_core_node_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_mocks.mdx b/api_docs/kbn_core_node_server_mocks.mdx index bb499ed6d6aee..2353acde456b1 100644 --- a/api_docs/kbn_core_node_server_mocks.mdx +++ b/api_docs/kbn_core_node_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-mocks title: "@kbn/core-node-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-mocks'] --- import kbnCoreNodeServerMocksObj from './kbn_core_node_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser.mdx b/api_docs/kbn_core_notifications_browser.mdx index 7183fe2e7661e..7457690f913bb 100644 --- a/api_docs/kbn_core_notifications_browser.mdx +++ b/api_docs/kbn_core_notifications_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser title: "@kbn/core-notifications-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser'] --- import kbnCoreNotificationsBrowserObj from './kbn_core_notifications_browser.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_internal.mdx b/api_docs/kbn_core_notifications_browser_internal.mdx index ded66b5298d2e..40b1f8be7dfe9 100644 --- a/api_docs/kbn_core_notifications_browser_internal.mdx +++ b/api_docs/kbn_core_notifications_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-internal title: "@kbn/core-notifications-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-internal'] --- import kbnCoreNotificationsBrowserInternalObj from './kbn_core_notifications_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_mocks.mdx b/api_docs/kbn_core_notifications_browser_mocks.mdx index dacafd5c07ea9..287c8a74fad4b 100644 --- a/api_docs/kbn_core_notifications_browser_mocks.mdx +++ b/api_docs/kbn_core_notifications_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-mocks title: "@kbn/core-notifications-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-mocks'] --- import kbnCoreNotificationsBrowserMocksObj from './kbn_core_notifications_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser.mdx b/api_docs/kbn_core_overlays_browser.mdx index 44df6622c0612..5b1e3101a2ffa 100644 --- a/api_docs/kbn_core_overlays_browser.mdx +++ b/api_docs/kbn_core_overlays_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser title: "@kbn/core-overlays-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser'] --- import kbnCoreOverlaysBrowserObj from './kbn_core_overlays_browser.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_internal.mdx b/api_docs/kbn_core_overlays_browser_internal.mdx index 45c728dd2212e..dd64cfe29323b 100644 --- a/api_docs/kbn_core_overlays_browser_internal.mdx +++ b/api_docs/kbn_core_overlays_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-internal title: "@kbn/core-overlays-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-internal'] --- import kbnCoreOverlaysBrowserInternalObj from './kbn_core_overlays_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_mocks.mdx b/api_docs/kbn_core_overlays_browser_mocks.mdx index 45a51da94d143..0fb419fdcb733 100644 --- a/api_docs/kbn_core_overlays_browser_mocks.mdx +++ b/api_docs/kbn_core_overlays_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-mocks title: "@kbn/core-overlays-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-mocks'] --- import kbnCoreOverlaysBrowserMocksObj from './kbn_core_overlays_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser.mdx b/api_docs/kbn_core_plugins_browser.mdx index 656221274a163..3ba18684a44f7 100644 --- a/api_docs/kbn_core_plugins_browser.mdx +++ b/api_docs/kbn_core_plugins_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser title: "@kbn/core-plugins-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser'] --- import kbnCorePluginsBrowserObj from './kbn_core_plugins_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser_mocks.mdx b/api_docs/kbn_core_plugins_browser_mocks.mdx index 266a89924e2d2..994dafc58a4d8 100644 --- a/api_docs/kbn_core_plugins_browser_mocks.mdx +++ b/api_docs/kbn_core_plugins_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser-mocks title: "@kbn/core-plugins-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser-mocks'] --- import kbnCorePluginsBrowserMocksObj from './kbn_core_plugins_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server.mdx b/api_docs/kbn_core_plugins_server.mdx index 300ef65282260..5dd09363bf9e3 100644 --- a/api_docs/kbn_core_plugins_server.mdx +++ b/api_docs/kbn_core_plugins_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server title: "@kbn/core-plugins-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server'] --- import kbnCorePluginsServerObj from './kbn_core_plugins_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server_mocks.mdx b/api_docs/kbn_core_plugins_server_mocks.mdx index 6ea7fb7d28df2..b067e04e1ec6c 100644 --- a/api_docs/kbn_core_plugins_server_mocks.mdx +++ b/api_docs/kbn_core_plugins_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server-mocks title: "@kbn/core-plugins-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server-mocks'] --- import kbnCorePluginsServerMocksObj from './kbn_core_plugins_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index dddd9131ec4a9..3eec8d4274255 100644 --- a/api_docs/kbn_core_preboot_server.mdx +++ b/api_docs/kbn_core_preboot_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server title: "@kbn/core-preboot-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server'] --- import kbnCorePrebootServerObj from './kbn_core_preboot_server.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server_mocks.mdx b/api_docs/kbn_core_preboot_server_mocks.mdx index 6ef6c334f6c9f..192e03884a75b 100644 --- a/api_docs/kbn_core_preboot_server_mocks.mdx +++ b/api_docs/kbn_core_preboot_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server-mocks title: "@kbn/core-preboot-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server-mocks'] --- import kbnCorePrebootServerMocksObj from './kbn_core_preboot_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_browser_mocks.mdx b/api_docs/kbn_core_rendering_browser_mocks.mdx index b4ebbd40acce0..4b9a512bc8fcb 100644 --- a/api_docs/kbn_core_rendering_browser_mocks.mdx +++ b/api_docs/kbn_core_rendering_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-browser-mocks title: "@kbn/core-rendering-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-browser-mocks'] --- import kbnCoreRenderingBrowserMocksObj from './kbn_core_rendering_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_internal.mdx b/api_docs/kbn_core_rendering_server_internal.mdx index 8be246dd7c86a..10af856edf809 100644 --- a/api_docs/kbn_core_rendering_server_internal.mdx +++ b/api_docs/kbn_core_rendering_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-internal title: "@kbn/core-rendering-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-internal'] --- import kbnCoreRenderingServerInternalObj from './kbn_core_rendering_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_mocks.mdx b/api_docs/kbn_core_rendering_server_mocks.mdx index 9c8aa99884803..4afbd0e98e994 100644 --- a/api_docs/kbn_core_rendering_server_mocks.mdx +++ b/api_docs/kbn_core_rendering_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-mocks title: "@kbn/core-rendering-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-mocks'] --- import kbnCoreRenderingServerMocksObj from './kbn_core_rendering_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_root_server_internal.mdx b/api_docs/kbn_core_root_server_internal.mdx index 50a284aea720e..badce6d9b916d 100644 --- a/api_docs/kbn_core_root_server_internal.mdx +++ b/api_docs/kbn_core_root_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-root-server-internal title: "@kbn/core-root-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-root-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-root-server-internal'] --- import kbnCoreRootServerInternalObj from './kbn_core_root_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index cbfa1a3be1252..4d1ade84be9b0 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.mdx +++ b/api_docs/kbn_core_saved_objects_api_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-browser title: "@kbn/core-saved-objects-api-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-browser plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-browser'] --- import kbnCoreSavedObjectsApiBrowserObj from './kbn_core_saved_objects_api_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index 1807f6dd43bfe..a683ee120aba9 100644 --- a/api_docs/kbn_core_saved_objects_api_server.mdx +++ b/api_docs/kbn_core_saved_objects_api_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server title: "@kbn/core-saved-objects-api-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx index 8ac7220435334..0a5441e6c55b2 100644 --- a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-mocks title: "@kbn/core-saved-objects-api-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server-mocks'] --- import kbnCoreSavedObjectsApiServerMocksObj from './kbn_core_saved_objects_api_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_internal.mdx b/api_docs/kbn_core_saved_objects_base_server_internal.mdx index 693e6123f8508..d29fa9e4483f7 100644 --- a/api_docs/kbn_core_saved_objects_base_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-internal title: "@kbn/core-saved-objects-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-internal'] --- import kbnCoreSavedObjectsBaseServerInternalObj from './kbn_core_saved_objects_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx index 0035c74b068df..697262b71b7ba 100644 --- a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-mocks title: "@kbn/core-saved-objects-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-mocks'] --- import kbnCoreSavedObjectsBaseServerMocksObj from './kbn_core_saved_objects_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser.mdx b/api_docs/kbn_core_saved_objects_browser.mdx index a97a1930db0e3..dffbe045e0cd6 100644 --- a/api_docs/kbn_core_saved_objects_browser.mdx +++ b/api_docs/kbn_core_saved_objects_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser title: "@kbn/core-saved-objects-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser'] --- import kbnCoreSavedObjectsBrowserObj from './kbn_core_saved_objects_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_internal.mdx b/api_docs/kbn_core_saved_objects_browser_internal.mdx index 25dc1e5630dc3..9cffeee08182d 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.mdx +++ b/api_docs/kbn_core_saved_objects_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-internal title: "@kbn/core-saved-objects-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-internal'] --- import kbnCoreSavedObjectsBrowserInternalObj from './kbn_core_saved_objects_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_mocks.mdx b/api_docs/kbn_core_saved_objects_browser_mocks.mdx index 001abf71565f8..cc0757aee2f95 100644 --- a/api_docs/kbn_core_saved_objects_browser_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-mocks title: "@kbn/core-saved-objects-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-mocks'] --- import kbnCoreSavedObjectsBrowserMocksObj from './kbn_core_saved_objects_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index eefb17d1ecb7e..a8084f14ffd3b 100644 --- a/api_docs/kbn_core_saved_objects_common.mdx +++ b/api_docs/kbn_core_saved_objects_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-common title: "@kbn/core-saved-objects-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-common plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-common'] --- import kbnCoreSavedObjectsCommonObj from './kbn_core_saved_objects_common.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx index b86c754b683a4..3802848464e71 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-internal title: "@kbn/core-saved-objects-import-export-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-internal'] --- import kbnCoreSavedObjectsImportExportServerInternalObj from './kbn_core_saved_objects_import_export_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx index 177d77c6d48e9..dcc24edc9c5f5 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-mocks title: "@kbn/core-saved-objects-import-export-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-mocks'] --- import kbnCoreSavedObjectsImportExportServerMocksObj from './kbn_core_saved_objects_import_export_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx index ee67a1af3d9e9..0eb4e9216130b 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-internal title: "@kbn/core-saved-objects-migration-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-internal'] --- import kbnCoreSavedObjectsMigrationServerInternalObj from './kbn_core_saved_objects_migration_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx index 66be5deb12f6d..951d86ad2df82 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-mocks title: "@kbn/core-saved-objects-migration-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-mocks'] --- import kbnCoreSavedObjectsMigrationServerMocksObj from './kbn_core_saved_objects_migration_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index c8018095c9045..5e110d387a563 100644 --- a/api_docs/kbn_core_saved_objects_server.mdx +++ b/api_docs/kbn_core_saved_objects_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server title: "@kbn/core-saved-objects-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server'] --- import kbnCoreSavedObjectsServerObj from './kbn_core_saved_objects_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_internal.mdx b/api_docs/kbn_core_saved_objects_server_internal.mdx index f801dcc750401..529b309fdd3c7 100644 --- a/api_docs/kbn_core_saved_objects_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-internal title: "@kbn/core-saved-objects-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-internal'] --- import kbnCoreSavedObjectsServerInternalObj from './kbn_core_saved_objects_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_mocks.mdx b/api_docs/kbn_core_saved_objects_server_mocks.mdx index c0f0e1507d36b..980928616a6da 100644 --- a/api_docs/kbn_core_saved_objects_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-mocks title: "@kbn/core-saved-objects-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-mocks'] --- import kbnCoreSavedObjectsServerMocksObj from './kbn_core_saved_objects_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_utils_server.mdx b/api_docs/kbn_core_saved_objects_utils_server.mdx index 99ff22c802e51..32433cc490bee 100644 --- a/api_docs/kbn_core_saved_objects_utils_server.mdx +++ b/api_docs/kbn_core_saved_objects_utils_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-utils-server title: "@kbn/core-saved-objects-utils-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-utils-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-utils-server'] --- import kbnCoreSavedObjectsUtilsServerObj from './kbn_core_saved_objects_utils_server.devdocs.json'; diff --git a/api_docs/kbn_core_status_common.mdx b/api_docs/kbn_core_status_common.mdx index b7dea67aa296d..647d18c24abcf 100644 --- a/api_docs/kbn_core_status_common.mdx +++ b/api_docs/kbn_core_status_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common title: "@kbn/core-status-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common'] --- import kbnCoreStatusCommonObj from './kbn_core_status_common.devdocs.json'; diff --git a/api_docs/kbn_core_status_common_internal.mdx b/api_docs/kbn_core_status_common_internal.mdx index b84a9a5b10631..a5f5932e17a7d 100644 --- a/api_docs/kbn_core_status_common_internal.mdx +++ b/api_docs/kbn_core_status_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common-internal title: "@kbn/core-status-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common-internal'] --- import kbnCoreStatusCommonInternalObj from './kbn_core_status_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server.mdx b/api_docs/kbn_core_status_server.mdx index 19077b75a7087..fc88feddaebb5 100644 --- a/api_docs/kbn_core_status_server.mdx +++ b/api_docs/kbn_core_status_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server title: "@kbn/core-status-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server'] --- import kbnCoreStatusServerObj from './kbn_core_status_server.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_internal.mdx b/api_docs/kbn_core_status_server_internal.mdx index 8cee9aa6d96dc..c481d0b18d2f1 100644 --- a/api_docs/kbn_core_status_server_internal.mdx +++ b/api_docs/kbn_core_status_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-internal title: "@kbn/core-status-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-internal'] --- import kbnCoreStatusServerInternalObj from './kbn_core_status_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_mocks.mdx b/api_docs/kbn_core_status_server_mocks.mdx index ac9655111b722..7883b70038955 100644 --- a/api_docs/kbn_core_status_server_mocks.mdx +++ b/api_docs/kbn_core_status_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-mocks title: "@kbn/core-status-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-mocks'] --- import kbnCoreStatusServerMocksObj from './kbn_core_status_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx index 357b5a4428a6f..72d0967423861 100644 --- a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx +++ b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-deprecations-getters title: "@kbn/core-test-helpers-deprecations-getters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-deprecations-getters plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-deprecations-getters'] --- import kbnCoreTestHelpersDeprecationsGettersObj from './kbn_core_test_helpers_deprecations_getters.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx index 28cf4c55b2786..f28ebd232b777 100644 --- a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx +++ b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-http-setup-browser title: "@kbn/core-test-helpers-http-setup-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-http-setup-browser plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-http-setup-browser'] --- import kbnCoreTestHelpersHttpSetupBrowserObj from './kbn_core_test_helpers_http_setup_browser.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_kbn_server.mdx b/api_docs/kbn_core_test_helpers_kbn_server.mdx index cc00e1f527394..5731cb092af07 100644 --- a/api_docs/kbn_core_test_helpers_kbn_server.mdx +++ b/api_docs/kbn_core_test_helpers_kbn_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-kbn-server title: "@kbn/core-test-helpers-kbn-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-kbn-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-kbn-server'] --- import kbnCoreTestHelpersKbnServerObj from './kbn_core_test_helpers_kbn_server.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx index 74e8e5f1838a9..34a71628f265a 100644 --- a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx +++ b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-so-type-serializer title: "@kbn/core-test-helpers-so-type-serializer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-so-type-serializer plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-so-type-serializer'] --- import kbnCoreTestHelpersSoTypeSerializerObj from './kbn_core_test_helpers_so_type_serializer.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_test_utils.mdx b/api_docs/kbn_core_test_helpers_test_utils.mdx index 17fe928e96281..0ed075823dc18 100644 --- a/api_docs/kbn_core_test_helpers_test_utils.mdx +++ b/api_docs/kbn_core_test_helpers_test_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-test-utils title: "@kbn/core-test-helpers-test-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-test-utils plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-test-utils'] --- import kbnCoreTestHelpersTestUtilsObj from './kbn_core_test_helpers_test_utils.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser.mdx b/api_docs/kbn_core_theme_browser.mdx index ebd2bb1ad9fe5..22d14e0a6a2fa 100644 --- a/api_docs/kbn_core_theme_browser.mdx +++ b/api_docs/kbn_core_theme_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser title: "@kbn/core-theme-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] --- import kbnCoreThemeBrowserObj from './kbn_core_theme_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index 7b6fc04762a3e..7409f81e1e498 100644 --- a/api_docs/kbn_core_theme_browser_mocks.mdx +++ b/api_docs/kbn_core_theme_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-mocks title: "@kbn/core-theme-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-mocks'] --- import kbnCoreThemeBrowserMocksObj from './kbn_core_theme_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser.mdx b/api_docs/kbn_core_ui_settings_browser.mdx index 54b7e96f1172f..92afe9eb9d7e5 100644 --- a/api_docs/kbn_core_ui_settings_browser.mdx +++ b/api_docs/kbn_core_ui_settings_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser title: "@kbn/core-ui-settings-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser'] --- import kbnCoreUiSettingsBrowserObj from './kbn_core_ui_settings_browser.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_internal.mdx b/api_docs/kbn_core_ui_settings_browser_internal.mdx index 783594aa9d8cd..f40b0a1777c3f 100644 --- a/api_docs/kbn_core_ui_settings_browser_internal.mdx +++ b/api_docs/kbn_core_ui_settings_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-internal title: "@kbn/core-ui-settings-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-internal'] --- import kbnCoreUiSettingsBrowserInternalObj from './kbn_core_ui_settings_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_mocks.mdx b/api_docs/kbn_core_ui_settings_browser_mocks.mdx index 1efaa87e91ced..f6b53dd7d2044 100644 --- a/api_docs/kbn_core_ui_settings_browser_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-mocks title: "@kbn/core-ui-settings-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-mocks'] --- import kbnCoreUiSettingsBrowserMocksObj from './kbn_core_ui_settings_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_common.mdx b/api_docs/kbn_core_ui_settings_common.mdx index a922b457f30ed..07eca64b58269 100644 --- a/api_docs/kbn_core_ui_settings_common.mdx +++ b/api_docs/kbn_core_ui_settings_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-common title: "@kbn/core-ui-settings-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-common plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-common'] --- import kbnCoreUiSettingsCommonObj from './kbn_core_ui_settings_common.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server.mdx b/api_docs/kbn_core_ui_settings_server.mdx index 8740db46fd7de..f11b058e08bad 100644 --- a/api_docs/kbn_core_ui_settings_server.mdx +++ b/api_docs/kbn_core_ui_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server title: "@kbn/core-ui-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server'] --- import kbnCoreUiSettingsServerObj from './kbn_core_ui_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_internal.mdx b/api_docs/kbn_core_ui_settings_server_internal.mdx index 47ec719e0404c..49ac9e4aa3f1d 100644 --- a/api_docs/kbn_core_ui_settings_server_internal.mdx +++ b/api_docs/kbn_core_ui_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-internal title: "@kbn/core-ui-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-internal'] --- import kbnCoreUiSettingsServerInternalObj from './kbn_core_ui_settings_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_mocks.mdx b/api_docs/kbn_core_ui_settings_server_mocks.mdx index 4ca8b9188d0b2..893693c710eb0 100644 --- a/api_docs/kbn_core_ui_settings_server_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-mocks title: "@kbn/core-ui-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-mocks'] --- import kbnCoreUiSettingsServerMocksObj from './kbn_core_ui_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server.mdx b/api_docs/kbn_core_usage_data_server.mdx index 4d100624512d7..5c834c7985fe6 100644 --- a/api_docs/kbn_core_usage_data_server.mdx +++ b/api_docs/kbn_core_usage_data_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server title: "@kbn/core-usage-data-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server'] --- import kbnCoreUsageDataServerObj from './kbn_core_usage_data_server.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_internal.mdx b/api_docs/kbn_core_usage_data_server_internal.mdx index 9e4ce4251cb55..9ac271c76b048 100644 --- a/api_docs/kbn_core_usage_data_server_internal.mdx +++ b/api_docs/kbn_core_usage_data_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-internal title: "@kbn/core-usage-data-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-internal'] --- import kbnCoreUsageDataServerInternalObj from './kbn_core_usage_data_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_mocks.mdx b/api_docs/kbn_core_usage_data_server_mocks.mdx index 1e513ea1fb1d9..61cd48548beee 100644 --- a/api_docs/kbn_core_usage_data_server_mocks.mdx +++ b/api_docs/kbn_core_usage_data_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-mocks title: "@kbn/core-usage-data-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-mocks'] --- import kbnCoreUsageDataServerMocksObj from './kbn_core_usage_data_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server.mdx b/api_docs/kbn_core_user_settings_server.mdx index c5ad8b74ac186..1ffabd4d5826e 100644 --- a/api_docs/kbn_core_user_settings_server.mdx +++ b/api_docs/kbn_core_user_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server title: "@kbn/core-user-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server'] --- import kbnCoreUserSettingsServerObj from './kbn_core_user_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server_internal.mdx b/api_docs/kbn_core_user_settings_server_internal.mdx index b6a64a1eab115..12ddaf035fc2e 100644 --- a/api_docs/kbn_core_user_settings_server_internal.mdx +++ b/api_docs/kbn_core_user_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server-internal title: "@kbn/core-user-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server-internal plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server-internal'] --- import kbnCoreUserSettingsServerInternalObj from './kbn_core_user_settings_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server_mocks.mdx b/api_docs/kbn_core_user_settings_server_mocks.mdx index 07fabb2446d55..2e04904075c70 100644 --- a/api_docs/kbn_core_user_settings_server_mocks.mdx +++ b/api_docs/kbn_core_user_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server-mocks title: "@kbn/core-user-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server-mocks'] --- import kbnCoreUserSettingsServerMocksObj from './kbn_core_user_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_crypto.mdx b/api_docs/kbn_crypto.mdx index c0ee403a2f79f..4355166d2051c 100644 --- a/api_docs/kbn_crypto.mdx +++ b/api_docs/kbn_crypto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto title: "@kbn/crypto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto'] --- import kbnCryptoObj from './kbn_crypto.devdocs.json'; diff --git a/api_docs/kbn_crypto_browser.mdx b/api_docs/kbn_crypto_browser.mdx index 2dfd03b92465c..1f3f864739cab 100644 --- a/api_docs/kbn_crypto_browser.mdx +++ b/api_docs/kbn_crypto_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto-browser title: "@kbn/crypto-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto-browser plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_custom_integrations.mdx b/api_docs/kbn_custom_integrations.mdx index c07f72fce212d..c81fd5690455e 100644 --- a/api_docs/kbn_custom_integrations.mdx +++ b/api_docs/kbn_custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-integrations title: "@kbn/custom-integrations" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-integrations plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-integrations'] --- import kbnCustomIntegrationsObj from './kbn_custom_integrations.devdocs.json'; diff --git a/api_docs/kbn_cypress_config.mdx b/api_docs/kbn_cypress_config.mdx index f23e8c0f1fbd8..4c4642432b108 100644 --- a/api_docs/kbn_cypress_config.mdx +++ b/api_docs/kbn_cypress_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cypress-config title: "@kbn/cypress-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cypress-config plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cypress-config'] --- import kbnCypressConfigObj from './kbn_cypress_config.devdocs.json'; diff --git a/api_docs/kbn_data_service.mdx b/api_docs/kbn_data_service.mdx index 8d50a3b93bbf4..afa7dd603786e 100644 --- a/api_docs/kbn_data_service.mdx +++ b/api_docs/kbn_data_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-service title: "@kbn/data-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-service plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-service'] --- import kbnDataServiceObj from './kbn_data_service.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index 1a6dd93e3a571..808aa13b21c1d 100644 --- a/api_docs/kbn_datemath.mdx +++ b/api_docs/kbn_datemath.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-datemath title: "@kbn/datemath" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/datemath plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_analytics.mdx b/api_docs/kbn_deeplinks_analytics.mdx index aebf2a9e4af82..4c6e93acbd52f 100644 --- a/api_docs/kbn_deeplinks_analytics.mdx +++ b/api_docs/kbn_deeplinks_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-analytics title: "@kbn/deeplinks-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-analytics plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-analytics'] --- import kbnDeeplinksAnalyticsObj from './kbn_deeplinks_analytics.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_devtools.mdx b/api_docs/kbn_deeplinks_devtools.mdx index b6514e9a33253..37e74fc743a49 100644 --- a/api_docs/kbn_deeplinks_devtools.mdx +++ b/api_docs/kbn_deeplinks_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-devtools title: "@kbn/deeplinks-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-devtools plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-devtools'] --- import kbnDeeplinksDevtoolsObj from './kbn_deeplinks_devtools.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_management.mdx b/api_docs/kbn_deeplinks_management.mdx index 29e4872352094..2f80038899710 100644 --- a/api_docs/kbn_deeplinks_management.mdx +++ b/api_docs/kbn_deeplinks_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-management title: "@kbn/deeplinks-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-management plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-management'] --- import kbnDeeplinksManagementObj from './kbn_deeplinks_management.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_ml.mdx b/api_docs/kbn_deeplinks_ml.mdx index 168d7906e53e9..fa818712486d1 100644 --- a/api_docs/kbn_deeplinks_ml.mdx +++ b/api_docs/kbn_deeplinks_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-ml title: "@kbn/deeplinks-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-ml plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-ml'] --- import kbnDeeplinksMlObj from './kbn_deeplinks_ml.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_observability.mdx b/api_docs/kbn_deeplinks_observability.mdx index c45567aa80526..e337c7d60eb51 100644 --- a/api_docs/kbn_deeplinks_observability.mdx +++ b/api_docs/kbn_deeplinks_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-observability title: "@kbn/deeplinks-observability" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-observability plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-observability'] --- import kbnDeeplinksObservabilityObj from './kbn_deeplinks_observability.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_search.mdx b/api_docs/kbn_deeplinks_search.mdx index 05048e4e6052e..d741f660e745b 100644 --- a/api_docs/kbn_deeplinks_search.mdx +++ b/api_docs/kbn_deeplinks_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-search title: "@kbn/deeplinks-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-search plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-search'] --- import kbnDeeplinksSearchObj from './kbn_deeplinks_search.devdocs.json'; diff --git a/api_docs/kbn_default_nav_analytics.mdx b/api_docs/kbn_default_nav_analytics.mdx index 960657f98b0ed..63387d4038d79 100644 --- a/api_docs/kbn_default_nav_analytics.mdx +++ b/api_docs/kbn_default_nav_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-analytics title: "@kbn/default-nav-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-analytics plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-analytics'] --- import kbnDefaultNavAnalyticsObj from './kbn_default_nav_analytics.devdocs.json'; diff --git a/api_docs/kbn_default_nav_devtools.mdx b/api_docs/kbn_default_nav_devtools.mdx index ab3f1edcd62bc..550b249527f10 100644 --- a/api_docs/kbn_default_nav_devtools.mdx +++ b/api_docs/kbn_default_nav_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-devtools title: "@kbn/default-nav-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-devtools plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-devtools'] --- import kbnDefaultNavDevtoolsObj from './kbn_default_nav_devtools.devdocs.json'; diff --git a/api_docs/kbn_default_nav_management.mdx b/api_docs/kbn_default_nav_management.mdx index 3a15b52e304ef..11472edda4b09 100644 --- a/api_docs/kbn_default_nav_management.mdx +++ b/api_docs/kbn_default_nav_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-management title: "@kbn/default-nav-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-management plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-management'] --- import kbnDefaultNavManagementObj from './kbn_default_nav_management.devdocs.json'; diff --git a/api_docs/kbn_default_nav_ml.mdx b/api_docs/kbn_default_nav_ml.mdx index c49781680b955..316dbc402e87e 100644 --- a/api_docs/kbn_default_nav_ml.mdx +++ b/api_docs/kbn_default_nav_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-ml title: "@kbn/default-nav-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-ml plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-ml'] --- import kbnDefaultNavMlObj from './kbn_default_nav_ml.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index 2c57401c9245d..f4cd437be43a8 100644 --- a/api_docs/kbn_dev_cli_errors.mdx +++ b/api_docs/kbn_dev_cli_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-errors title: "@kbn/dev-cli-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-errors plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-errors'] --- import kbnDevCliErrorsObj from './kbn_dev_cli_errors.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_runner.devdocs.json b/api_docs/kbn_dev_cli_runner.devdocs.json index d0d8b3be799bc..f1c0f5f34bed9 100644 --- a/api_docs/kbn_dev_cli_runner.devdocs.json +++ b/api_docs/kbn_dev_cli_runner.devdocs.json @@ -1155,6 +1155,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/dev-cli-runner", + "id": "def-common.FlagOptions.examples", + "type": "string", + "tags": [], + "label": "examples", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-dev-cli-runner/src/flags.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/dev-cli-runner", "id": "def-common.FlagOptions.alias", diff --git a/api_docs/kbn_dev_cli_runner.mdx b/api_docs/kbn_dev_cli_runner.mdx index 155ea894b65ca..18864e112a8e5 100644 --- a/api_docs/kbn_dev_cli_runner.mdx +++ b/api_docs/kbn_dev_cli_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-runner title: "@kbn/dev-cli-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-runner plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-runner'] --- import kbnDevCliRunnerObj from './kbn_dev_cli_runner.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kiban | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 101 | 0 | 85 | 0 | +| 102 | 0 | 86 | 0 | ## Common diff --git a/api_docs/kbn_dev_proc_runner.mdx b/api_docs/kbn_dev_proc_runner.mdx index 2aaa075f7037c..266bd9d69b271 100644 --- a/api_docs/kbn_dev_proc_runner.mdx +++ b/api_docs/kbn_dev_proc_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-proc-runner title: "@kbn/dev-proc-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-proc-runner plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-proc-runner'] --- import kbnDevProcRunnerObj from './kbn_dev_proc_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_utils.mdx b/api_docs/kbn_dev_utils.mdx index e8d8ec623e806..f8c2db7bc8c17 100644 --- a/api_docs/kbn_dev_utils.mdx +++ b/api_docs/kbn_dev_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-utils title: "@kbn/dev-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-utils plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_discover_utils.mdx b/api_docs/kbn_discover_utils.mdx index 93f6c59c4acd3..8f3e1fcfd9aff 100644 --- a/api_docs/kbn_discover_utils.mdx +++ b/api_docs/kbn_discover_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-discover-utils title: "@kbn/discover-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/discover-utils plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-utils'] --- import kbnDiscoverUtilsObj from './kbn_discover_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index 0d079b84e7b1e..329b929061274 100644 --- a/api_docs/kbn_doc_links.mdx +++ b/api_docs/kbn_doc_links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-doc-links title: "@kbn/doc-links" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/doc-links plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/doc-links'] --- import kbnDocLinksObj from './kbn_doc_links.devdocs.json'; diff --git a/api_docs/kbn_docs_utils.mdx b/api_docs/kbn_docs_utils.mdx index d93f7bf0216ce..a3a33f34de78c 100644 --- a/api_docs/kbn_docs_utils.mdx +++ b/api_docs/kbn_docs_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-docs-utils title: "@kbn/docs-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/docs-utils plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_dom_drag_drop.mdx b/api_docs/kbn_dom_drag_drop.mdx index 8916af4df9fb2..0873b2073c433 100644 --- a/api_docs/kbn_dom_drag_drop.mdx +++ b/api_docs/kbn_dom_drag_drop.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dom-drag-drop title: "@kbn/dom-drag-drop" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dom-drag-drop plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dom-drag-drop'] --- import kbnDomDragDropObj from './kbn_dom_drag_drop.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index 014c18a8cbda5..7663d904509cd 100644 --- a/api_docs/kbn_ebt_tools.mdx +++ b/api_docs/kbn_ebt_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ebt-tools title: "@kbn/ebt-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ebt-tools plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_ecs.mdx b/api_docs/kbn_ecs.mdx index 44125b1345abf..08ec7b97c2eae 100644 --- a/api_docs/kbn_ecs.mdx +++ b/api_docs/kbn_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs title: "@kbn/ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs'] --- import kbnEcsObj from './kbn_ecs.devdocs.json'; diff --git a/api_docs/kbn_ecs_data_quality_dashboard.mdx b/api_docs/kbn_ecs_data_quality_dashboard.mdx index 11c9c4c666074..1f2c875379748 100644 --- a/api_docs/kbn_ecs_data_quality_dashboard.mdx +++ b/api_docs/kbn_ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs-data-quality-dashboard title: "@kbn/ecs-data-quality-dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs-data-quality-dashboard plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs-data-quality-dashboard'] --- import kbnEcsDataQualityDashboardObj from './kbn_ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant.mdx b/api_docs/kbn_elastic_assistant.mdx index 625952ef85ad0..5186c443dde7d 100644 --- a/api_docs/kbn_elastic_assistant.mdx +++ b/api_docs/kbn_elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant title: "@kbn/elastic-assistant" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant'] --- import kbnElasticAssistantObj from './kbn_elastic_assistant.devdocs.json'; diff --git a/api_docs/kbn_es.mdx b/api_docs/kbn_es.mdx index dba47e1f237fb..03cf418521b1f 100644 --- a/api_docs/kbn_es.mdx +++ b/api_docs/kbn_es.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es title: "@kbn/es" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es'] --- import kbnEsObj from './kbn_es.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index d18fd02ff7f45..df9c1e659614e 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-archiver plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-archiver'] --- import kbnEsArchiverObj from './kbn_es_archiver.devdocs.json'; diff --git a/api_docs/kbn_es_errors.mdx b/api_docs/kbn_es_errors.mdx index 6dbc74478590d..c99a216c06111 100644 --- a/api_docs/kbn_es_errors.mdx +++ b/api_docs/kbn_es_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-errors title: "@kbn/es-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-errors plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-errors'] --- import kbnEsErrorsObj from './kbn_es_errors.devdocs.json'; diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index d02c064539f07..6190afdd38eb5 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-query title: "@kbn/es-query" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-query plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index 11c7eb5df7999..5dce4a1a3a937 100644 --- a/api_docs/kbn_es_types.mdx +++ b/api_docs/kbn_es_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-types title: "@kbn/es-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-types plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-types'] --- import kbnEsTypesObj from './kbn_es_types.devdocs.json'; diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index 04717e9eb912d..e8dd0c0e4700e 100644 --- a/api_docs/kbn_eslint_plugin_imports.mdx +++ b/api_docs/kbn_eslint_plugin_imports.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-eslint-plugin-imports title: "@kbn/eslint-plugin-imports" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/eslint-plugin-imports plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_common.mdx b/api_docs/kbn_event_annotation_common.mdx index 2a3a1828159c4..12445d95a71b1 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: 2023-09-25 +date: 2023-09-26 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 42750a0453395..69242c24cafca 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: 2023-09-25 +date: 2023-09-26 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 d82e33e0b9d44..4533a7a3ef6e5 100644 --- a/api_docs/kbn_expandable_flyout.mdx +++ b/api_docs/kbn_expandable_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-expandable-flyout title: "@kbn/expandable-flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/expandable-flyout plugin -date: 2023-09-25 +date: 2023-09-26 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 9b5d782319fba..90537ba6a0ff8 100644 --- a/api_docs/kbn_field_types.mdx +++ b/api_docs/kbn_field_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-types title: "@kbn/field-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-types plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index a85eddf18ee15..602c4c33e88c5 100644 --- a/api_docs/kbn_find_used_node_modules.mdx +++ b/api_docs/kbn_find_used_node_modules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-find-used-node-modules title: "@kbn/find-used-node-modules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/find-used-node-modules plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/find-used-node-modules'] --- import kbnFindUsedNodeModulesObj from './kbn_find_used_node_modules.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_services.mdx b/api_docs/kbn_ftr_common_functional_services.mdx index 64b1c2f280233..77bcf8ba462e6 100644 --- a/api_docs/kbn_ftr_common_functional_services.mdx +++ b/api_docs/kbn_ftr_common_functional_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-services title: "@kbn/ftr-common-functional-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-services plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-services'] --- import kbnFtrCommonFunctionalServicesObj from './kbn_ftr_common_functional_services.devdocs.json'; diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index 41e2065d3afbc..60e59baa20675 100644 --- a/api_docs/kbn_generate.mdx +++ b/api_docs/kbn_generate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate title: "@kbn/generate" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate plugin -date: 2023-09-25 +date: 2023-09-26 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 c4aa464f5ad50..fc3e4876cffc2 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: 2023-09-25 +date: 2023-09-26 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 d658eeb8b2af9..37db79322e58d 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_generate_csv_types.mdx b/api_docs/kbn_generate_csv_types.mdx index c454fe5b04c2e..b1132b6103bce 100644 --- a/api_docs/kbn_generate_csv_types.mdx +++ b/api_docs/kbn_generate_csv_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-csv-types title: "@kbn/generate-csv-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-csv-types plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv-types'] --- import kbnGenerateCsvTypesObj from './kbn_generate_csv_types.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index 0541492651bb6..e55278db4e551 100644 --- a/api_docs/kbn_guided_onboarding.mdx +++ b/api_docs/kbn_guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-guided-onboarding title: "@kbn/guided-onboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/guided-onboarding plugin -date: 2023-09-25 +date: 2023-09-26 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 14f64f21aba6d..4c6e2effb0139 100644 --- a/api_docs/kbn_handlebars.mdx +++ b/api_docs/kbn_handlebars.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-handlebars title: "@kbn/handlebars" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/handlebars plugin -date: 2023-09-25 +date: 2023-09-26 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 112dbaea3447b..8401ace9d2657 100644 --- a/api_docs/kbn_hapi_mocks.mdx +++ b/api_docs/kbn_hapi_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-hapi-mocks title: "@kbn/hapi-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/hapi-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 001d6acc2fa6d..a085749f4b626 100644 --- a/api_docs/kbn_health_gateway_server.mdx +++ b/api_docs/kbn_health_gateway_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-health-gateway-server title: "@kbn/health-gateway-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/health-gateway-server plugin -date: 2023-09-25 +date: 2023-09-26 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 d8ce739a1bc15..891f0c2d37a24 100644 --- a/api_docs/kbn_home_sample_data_card.mdx +++ b/api_docs/kbn_home_sample_data_card.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-card title: "@kbn/home-sample-data-card" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-card plugin -date: 2023-09-25 +date: 2023-09-26 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 1857796753c32..f75c0ab8043bd 100644 --- a/api_docs/kbn_home_sample_data_tab.mdx +++ b/api_docs/kbn_home_sample_data_tab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-tab title: "@kbn/home-sample-data-tab" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-tab plugin -date: 2023-09-25 +date: 2023-09-26 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 e35341e4a6138..7a89bc6590ade 100644 --- a/api_docs/kbn_i18n.mdx +++ b/api_docs/kbn_i18n.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n title: "@kbn/i18n" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n plugin -date: 2023-09-25 +date: 2023-09-26 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 0b68e1641af45..cca6dcbacf292 100644 --- a/api_docs/kbn_i18n_react.mdx +++ b/api_docs/kbn_i18n_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n-react title: "@kbn/i18n-react" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n-react plugin -date: 2023-09-25 +date: 2023-09-26 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 f476b2ec1fc4d..2aefadf71cbe7 100644 --- a/api_docs/kbn_import_resolver.mdx +++ b/api_docs/kbn_import_resolver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-import-resolver title: "@kbn/import-resolver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/import-resolver plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_infra_forge.mdx b/api_docs/kbn_infra_forge.mdx index e86d57f05bde6..a5880533eb557 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: 2023-09-25 +date: 2023-09-26 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 1eb782fb97a7a..66a6a08c5fdb4 100644 --- a/api_docs/kbn_interpreter.mdx +++ b/api_docs/kbn_interpreter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-interpreter title: "@kbn/interpreter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/interpreter plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index 3ff5c27cea928..0bb6c8b7a09ba 100644 --- a/api_docs/kbn_io_ts_utils.mdx +++ b/api_docs/kbn_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-io-ts-utils title: "@kbn/io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/io-ts-utils plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] --- import kbnIoTsUtilsObj from './kbn_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index de08cea9a52ea..36be9a0e48ca6 100644 --- a/api_docs/kbn_jest_serializers.mdx +++ b/api_docs/kbn_jest_serializers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-jest-serializers title: "@kbn/jest-serializers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/jest-serializers plugin -date: 2023-09-25 +date: 2023-09-26 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 b83426b8881f6..a63fc46f0313e 100644 --- a/api_docs/kbn_journeys.mdx +++ b/api_docs/kbn_journeys.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-journeys title: "@kbn/journeys" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/journeys plugin -date: 2023-09-25 +date: 2023-09-26 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 047032d25cb1c..54e12b071a7e6 100644 --- a/api_docs/kbn_json_ast.mdx +++ b/api_docs/kbn_json_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-ast title: "@kbn/json-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-ast plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-ast'] --- import kbnJsonAstObj from './kbn_json_ast.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 0e2b9839031d2..75c46c9c8179c 100644 --- a/api_docs/kbn_kibana_manifest_schema.mdx +++ b/api_docs/kbn_kibana_manifest_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-schema title: "@kbn/kibana-manifest-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-schema plugin -date: 2023-09-25 +date: 2023-09-26 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 dbef273cea48b..1487d68d7a125 100644 --- a/api_docs/kbn_language_documentation_popover.mdx +++ b/api_docs/kbn_language_documentation_popover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-language-documentation-popover title: "@kbn/language-documentation-popover" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/language-documentation-popover plugin -date: 2023-09-25 +date: 2023-09-26 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 c5c5681e3012a..175b0011e3d19 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-embeddable-utils'] --- import kbnLensEmbeddableUtilsObj from './kbn_lens_embeddable_utils.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index 743dfd6613d16..b8558845daaaa 100644 --- a/api_docs/kbn_logging.mdx +++ b/api_docs/kbn_logging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging title: "@kbn/logging" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging plugin -date: 2023-09-25 +date: 2023-09-26 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 5f11011b0bf7a..d384c6aadec78 100644 --- a/api_docs/kbn_logging_mocks.mdx +++ b/api_docs/kbn_logging_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging-mocks title: "@kbn/logging-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] --- import kbnLoggingMocksObj from './kbn_logging_mocks.devdocs.json'; diff --git a/api_docs/kbn_managed_vscode_config.mdx b/api_docs/kbn_managed_vscode_config.mdx index c9433e41a126e..f96b5a18b902d 100644 --- a/api_docs/kbn_managed_vscode_config.mdx +++ b/api_docs/kbn_managed_vscode_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-vscode-config title: "@kbn/managed-vscode-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-vscode-config plugin -date: 2023-09-25 +date: 2023-09-26 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 e0d6919349ad7..9aa3f098d4c82 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: 2023-09-25 +date: 2023-09-26 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_components_field_input.mdx b/api_docs/kbn_management_settings_components_field_input.mdx index b9a73ffc4f5d4..0bb2d8ba4a0bd 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: 2023-09-25 +date: 2023-09-26 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 8e8ea4b103db1..b583ce8dcc6db 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: 2023-09-25 +date: 2023-09-26 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_field_definition.mdx b/api_docs/kbn_management_settings_field_definition.mdx index b2f42e0616125..bd67c35e89736 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: 2023-09-25 +date: 2023-09-26 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 893d2328b22fa..76fec3f21812f 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: 2023-09-25 +date: 2023-09-26 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 ed99fa80766c4..9b1d2a0ceed39 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: 2023-09-25 +date: 2023-09-26 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 a403ae48283b7..0056c1744c93d 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: 2023-09-25 +date: 2023-09-26 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 49ba997e4f681..ebe1ee0e883a9 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: 2023-09-25 +date: 2023-09-26 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 bb2582bad4a12..46f63c66d97f4 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: 2023-09-25 +date: 2023-09-26 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 bc5b83226c36a..d5e8f5242d84e 100644 --- a/api_docs/kbn_mapbox_gl.mdx +++ b/api_docs/kbn_mapbox_gl.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mapbox-gl title: "@kbn/mapbox-gl" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mapbox-gl plugin -date: 2023-09-25 +date: 2023-09-26 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 83c17a794e6bb..8d8c184651886 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: 2023-09-25 +date: 2023-09-26 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 25c2ba0d5d608..bd774233e0d5b 100644 --- a/api_docs/kbn_ml_agg_utils.mdx +++ b/api_docs/kbn_ml_agg_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-agg-utils title: "@kbn/ml-agg-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-agg-utils plugin -date: 2023-09-25 +date: 2023-09-26 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 b83a4d4a6614d..98b498f4e6caa 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-anomaly-utils'] --- import kbnMlAnomalyUtilsObj from './kbn_ml_anomaly_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_category_validator.mdx b/api_docs/kbn_ml_category_validator.mdx index 4658a091d165e..f61c556d391c2 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: 2023-09-25 +date: 2023-09-26 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_data_frame_analytics_utils.mdx b/api_docs/kbn_ml_data_frame_analytics_utils.mdx index 3e748a58c2008..1c460b72b9076 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: 2023-09-25 +date: 2023-09-26 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 00ff6cd26b022..ce7198cc744ae 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: 2023-09-25 +date: 2023-09-26 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 4d7a4aa29a9ef..4b608ad59ead6 100644 --- a/api_docs/kbn_ml_date_picker.mdx +++ b/api_docs/kbn_ml_date_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-picker title: "@kbn/ml-date-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-picker plugin -date: 2023-09-25 +date: 2023-09-26 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 e0ab84aa0a179..023b1ed66e570 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: 2023-09-25 +date: 2023-09-26 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 3a12f3c49aa48..d893b4e63f288 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: 2023-09-25 +date: 2023-09-26 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 f06bc6d9963ae..07ff44c50e48d 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: 2023-09-25 +date: 2023-09-26 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 daacad5e7f5ca..5f3d421739ee4 100644 --- a/api_docs/kbn_ml_is_defined.mdx +++ b/api_docs/kbn_ml_is_defined.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-defined title: "@kbn/ml-is-defined" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-defined plugin -date: 2023-09-25 +date: 2023-09-26 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 464622aa3d617..7a1d61a31a821 100644 --- a/api_docs/kbn_ml_is_populated_object.mdx +++ b/api_docs/kbn_ml_is_populated_object.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-populated-object title: "@kbn/ml-is-populated-object" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-populated-object plugin -date: 2023-09-25 +date: 2023-09-26 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 f9a9bc821e106..e850a70fa8fbd 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: 2023-09-25 +date: 2023-09-26 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 ad7313b831f6a..6ed106a6ff05e 100644 --- a/api_docs/kbn_ml_local_storage.mdx +++ b/api_docs/kbn_ml_local_storage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-local-storage title: "@kbn/ml-local-storage" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-local-storage plugin -date: 2023-09-25 +date: 2023-09-26 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 403a7969d5e64..57378e46c6142 100644 --- a/api_docs/kbn_ml_nested_property.mdx +++ b/api_docs/kbn_ml_nested_property.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-nested-property title: "@kbn/ml-nested-property" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-nested-property plugin -date: 2023-09-25 +date: 2023-09-26 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 82b8dfff78846..ff04eac99a8a2 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: 2023-09-25 +date: 2023-09-26 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 3e94c66746972..dd27f6e0603e1 100644 --- a/api_docs/kbn_ml_query_utils.mdx +++ b/api_docs/kbn_ml_query_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-query-utils title: "@kbn/ml-query-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-query-utils plugin -date: 2023-09-25 +date: 2023-09-26 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 e647e7cbf750b..beb2b1d7d1704 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: 2023-09-25 +date: 2023-09-26 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 e2acd8ef3b8be..308331aafb6a9 100644 --- a/api_docs/kbn_ml_route_utils.mdx +++ b/api_docs/kbn_ml_route_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-route-utils title: "@kbn/ml-route-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-route-utils plugin -date: 2023-09-25 +date: 2023-09-26 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 dd1e17aff3e6d..8d3d359d9ee8a 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: 2023-09-25 +date: 2023-09-26 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 4ae8ec2d9dc65..987ef40c0498a 100644 --- a/api_docs/kbn_ml_string_hash.mdx +++ b/api_docs/kbn_ml_string_hash.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-string-hash title: "@kbn/ml-string-hash" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-string-hash plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_ml_trained_models_utils.devdocs.json b/api_docs/kbn_ml_trained_models_utils.devdocs.json index 4401041f76b06..d074c0826737e 100644 --- a/api_docs/kbn_ml_trained_models_utils.devdocs.json +++ b/api_docs/kbn_ml_trained_models_utils.devdocs.json @@ -19,7 +19,149 @@ "common": { "classes": [], "functions": [], - "interfaces": [], + "interfaces": [ + { + "parentPluginId": "@kbn/ml-trained-models-utils", + "id": "def-common.GetElserOptions", + "type": "Interface", + "tags": [], + "label": "GetElserOptions", + "description": [], + "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ml-trained-models-utils", + "id": "def-common.GetElserOptions.version", + "type": "CompoundType", + "tags": [], + "label": "version", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ml-trained-models-utils", + "scope": "common", + "docId": "kibKbnMlTrainedModelsUtilsPluginApi", + "section": "def-common.ElserVersion", + "text": "ElserVersion" + }, + " | undefined" + ], + "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ml-trained-models-utils", + "id": "def-common.ModelDefinition", + "type": "Interface", + "tags": [], + "label": "ModelDefinition", + "description": [], + "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ml-trained-models-utils", + "id": "def-common.ModelDefinition.version", + "type": "number", + "tags": [], + "label": "version", + "description": [], + "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-trained-models-utils", + "id": "def-common.ModelDefinition.config", + "type": "Uncategorized", + "tags": [], + "label": "config", + "description": [], + "signature": [ + "object" + ], + "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-trained-models-utils", + "id": "def-common.ModelDefinition.description", + "type": "string", + "tags": [], + "label": "description", + "description": [], + "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-trained-models-utils", + "id": "def-common.ModelDefinition.os", + "type": "string", + "tags": [], + "label": "os", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-trained-models-utils", + "id": "def-common.ModelDefinition.arch", + "type": "string", + "tags": [], + "label": "arch", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-trained-models-utils", + "id": "def-common.ModelDefinition.default", + "type": "CompoundType", + "tags": [], + "label": "default", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-trained-models-utils", + "id": "def-common.ModelDefinition.recommended", + "type": "CompoundType", + "tags": [], + "label": "recommended", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], "enums": [], "misc": [ { @@ -64,6 +206,58 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/ml-trained-models-utils", + "id": "def-common.ElasticModelId", + "type": "Type", + "tags": [], + "label": "ElasticModelId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ml-trained-models-utils", + "id": "def-common.ElserVersion", + "type": "Type", + "tags": [], + "label": "ElserVersion", + "description": [], + "signature": [ + "2 | 1" + ], + "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ml-trained-models-utils", + "id": "def-common.ModelDefinitionResponse", + "type": "Type", + "tags": [], + "label": "ModelDefinitionResponse", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ml-trained-models-utils", + "scope": "common", + "docId": "kibKbnMlTrainedModelsUtilsPluginApi", + "section": "def-common.ModelDefinition", + "text": "ModelDefinition" + }, + " & { name: string; }" + ], + "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/ml-trained-models-utils", "id": "def-common.SupportedPytorchTasksType", @@ -111,6 +305,29 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/ml-trained-models-utils", + "id": "def-common.ELASTIC_MODEL_DEFINITIONS", + "type": "Object", + "tags": [], + "label": "ELASTIC_MODEL_DEFINITIONS", + "description": [], + "signature": [ + "{ [x: string]: ", + { + "pluginId": "@kbn/ml-trained-models-utils", + "scope": "common", + "docId": "kibKbnMlTrainedModelsUtilsPluginApi", + "section": "def-common.ModelDefinition", + "text": "ModelDefinition" + }, + "; }" + ], + "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/ml-trained-models-utils", "id": "def-common.SUPPORTED_PYTORCH_TASKS", diff --git a/api_docs/kbn_ml_trained_models_utils.mdx b/api_docs/kbn_ml_trained_models_utils.mdx index c54e0d15eb6bd..826487526b1a4 100644 --- a/api_docs/kbn_ml_trained_models_utils.mdx +++ b/api_docs/kbn_ml_trained_models_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-trained-models-utils title: "@kbn/ml-trained-models-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-trained-models-utils plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-trained-models-utils'] --- import kbnMlTrainedModelsUtilsObj from './kbn_ml_trained_models_utils.devdocs.json'; @@ -21,13 +21,16 @@ Contact [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 8 | 0 | 8 | 0 | +| 22 | 0 | 22 | 0 | ## Common ### Objects +### Interfaces + + ### Consts, variables and types diff --git a/api_docs/kbn_ml_url_state.mdx b/api_docs/kbn_ml_url_state.mdx index fb0a0c56e0c6a..df893a97873fa 100644 --- a/api_docs/kbn_ml_url_state.mdx +++ b/api_docs/kbn_ml_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-url-state title: "@kbn/ml-url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-url-state plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-url-state'] --- import kbnMlUrlStateObj from './kbn_ml_url_state.devdocs.json'; diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index e6e6002c5160d..fd7f4ab280191 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-monaco title: "@kbn/monaco" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/monaco plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_object_versioning.mdx b/api_docs/kbn_object_versioning.mdx index 87e4107c558a8..a1f05e9ce3468 100644 --- a/api_docs/kbn_object_versioning.mdx +++ b/api_docs/kbn_object_versioning.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-object-versioning title: "@kbn/object-versioning" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/object-versioning plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/object-versioning'] --- import kbnObjectVersioningObj from './kbn_object_versioning.devdocs.json'; diff --git a/api_docs/kbn_observability_alert_details.mdx b/api_docs/kbn_observability_alert_details.mdx index 9233358b2e19c..0fd0d346fb57b 100644 --- a/api_docs/kbn_observability_alert_details.mdx +++ b/api_docs/kbn_observability_alert_details.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alert-details title: "@kbn/observability-alert-details" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alert-details plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alert-details'] --- import kbnObservabilityAlertDetailsObj from './kbn_observability_alert_details.devdocs.json'; diff --git a/api_docs/kbn_openapi_generator.devdocs.json b/api_docs/kbn_openapi_generator.devdocs.json new file mode 100644 index 0000000000000..9aaaea230439e --- /dev/null +++ b/api_docs/kbn_openapi_generator.devdocs.json @@ -0,0 +1,143 @@ +{ + "id": "@kbn/openapi-generator", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/openapi-generator", + "id": "def-common.generate", + "type": "Function", + "tags": [], + "label": "generate", + "description": [], + "signature": [ + "(config: ", + { + "pluginId": "@kbn/openapi-generator", + "scope": "common", + "docId": "kibKbnOpenapiGeneratorPluginApi", + "section": "def-common.GeneratorConfig", + "text": "GeneratorConfig" + }, + ") => Promise" + ], + "path": "packages/kbn-openapi-generator/src/openapi_generator.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/openapi-generator", + "id": "def-common.generate.$1", + "type": "Object", + "tags": [], + "label": "config", + "description": [], + "signature": [ + { + "pluginId": "@kbn/openapi-generator", + "scope": "common", + "docId": "kibKbnOpenapiGeneratorPluginApi", + "section": "def-common.GeneratorConfig", + "text": "GeneratorConfig" + } + ], + "path": "packages/kbn-openapi-generator/src/openapi_generator.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/openapi-generator", + "id": "def-common.runCli", + "type": "Function", + "tags": [], + "label": "runCli", + "description": [], + "signature": [ + "() => void" + ], + "path": "packages/kbn-openapi-generator/src/cli.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "@kbn/openapi-generator", + "id": "def-common.GeneratorConfig", + "type": "Interface", + "tags": [], + "label": "GeneratorConfig", + "description": [], + "path": "packages/kbn-openapi-generator/src/openapi_generator.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/openapi-generator", + "id": "def-common.GeneratorConfig.rootDir", + "type": "string", + "tags": [], + "label": "rootDir", + "description": [], + "path": "packages/kbn-openapi-generator/src/openapi_generator.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/openapi-generator", + "id": "def-common.GeneratorConfig.sourceGlob", + "type": "string", + "tags": [], + "label": "sourceGlob", + "description": [], + "path": "packages/kbn-openapi-generator/src/openapi_generator.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/openapi-generator", + "id": "def-common.GeneratorConfig.templateName", + "type": "string", + "tags": [], + "label": "templateName", + "description": [], + "signature": [ + "\"zod_operation_schema\"" + ], + "path": "packages/kbn-openapi-generator/src/openapi_generator.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_openapi_generator.mdx b/api_docs/kbn_openapi_generator.mdx new file mode 100644 index 0000000000000..f02eb69948148 --- /dev/null +++ b/api_docs/kbn_openapi_generator.mdx @@ -0,0 +1,33 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnOpenapiGeneratorPluginApi +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: 2023-09-26 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-generator'] +--- +import kbnOpenapiGeneratorObj from './kbn_openapi_generator.devdocs.json'; + + + +Contact [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 7 | 0 | 7 | 0 | + +## Common + +### Functions + + +### Interfaces + + diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index a292fa3b74e96..7e481ccde5b12 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer title: "@kbn/optimizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer plugin -date: 2023-09-25 +date: 2023-09-26 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 fb1356fac73e3..ba9ddba74cf0f 100644 --- a/api_docs/kbn_optimizer_webpack_helpers.mdx +++ b/api_docs/kbn_optimizer_webpack_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer-webpack-helpers title: "@kbn/optimizer-webpack-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer-webpack-helpers plugin -date: 2023-09-25 +date: 2023-09-26 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 6c9ee72777eed..1aa5700cf7f06 100644 --- a/api_docs/kbn_osquery_io_ts_types.mdx +++ b/api_docs/kbn_osquery_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-osquery-io-ts-types title: "@kbn/osquery-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/osquery-io-ts-types plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/osquery-io-ts-types'] --- import kbnOsqueryIoTsTypesObj from './kbn_osquery_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index f1e1597883753..239fbcac319dc 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.mdx +++ b/api_docs/kbn_performance_testing_dataset_extractor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-performance-testing-dataset-extractor title: "@kbn/performance-testing-dataset-extractor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/performance-testing-dataset-extractor plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/performance-testing-dataset-extractor'] --- import kbnPerformanceTestingDatasetExtractorObj from './kbn_performance_testing_dataset_extractor.devdocs.json'; diff --git a/api_docs/kbn_plugin_generator.mdx b/api_docs/kbn_plugin_generator.mdx index 24bfb029d6109..595ee7d2e7bef 100644 --- a/api_docs/kbn_plugin_generator.mdx +++ b/api_docs/kbn_plugin_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-generator title: "@kbn/plugin-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-generator plugin -date: 2023-09-25 +date: 2023-09-26 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 953511e39f2e3..da6040e368280 100644 --- a/api_docs/kbn_plugin_helpers.mdx +++ b/api_docs/kbn_plugin_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-helpers title: "@kbn/plugin-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-helpers plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_profiling_utils.mdx b/api_docs/kbn_profiling_utils.mdx index 0514e6150c891..31ca69386bd82 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: 2023-09-25 +date: 2023-09-26 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 c7ec2b6a93603..c7da703a0e30b 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: 2023-09-25 +date: 2023-09-26 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 0507895dffd49..90931f67f40ca 100644 --- a/api_docs/kbn_react_field.mdx +++ b/api_docs/kbn_react_field.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-field title: "@kbn/react-field" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-field plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_common.mdx b/api_docs/kbn_react_kibana_context_common.mdx index 704735f466ae5..4098bb11f2af2 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: 2023-09-25 +date: 2023-09-26 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 e88986d3607aa..12b1dd9e31b23 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: 2023-09-25 +date: 2023-09-26 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 11e05f741a2ac..ccb60475d5cac 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: 2023-09-25 +date: 2023-09-26 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 5ddab41b46838..6ddfd7eb25515 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: 2023-09-25 +date: 2023-09-26 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 83de93e3369ea..b446bab101000 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: 2023-09-25 +date: 2023-09-26 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 dca37ad6e56a4..ec5ba4a464554 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-mount'] --- import kbnReactKibanaMountObj from './kbn_react_kibana_mount.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index a68d4f826eb98..e912a795d439b 100644 --- a/api_docs/kbn_repo_file_maps.mdx +++ b/api_docs/kbn_repo_file_maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-file-maps title: "@kbn/repo-file-maps" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-file-maps plugin -date: 2023-09-25 +date: 2023-09-26 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 6f879cf7898a8..9ce023a023749 100644 --- a/api_docs/kbn_repo_linter.mdx +++ b/api_docs/kbn_repo_linter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-linter title: "@kbn/repo-linter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-linter plugin -date: 2023-09-25 +date: 2023-09-26 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 2f36028277cef..234244470fb24 100644 --- a/api_docs/kbn_repo_path.mdx +++ b/api_docs/kbn_repo_path.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-path title: "@kbn/repo-path" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-path plugin -date: 2023-09-25 +date: 2023-09-26 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 f227b7022b7f5..42e035a7cc161 100644 --- a/api_docs/kbn_repo_source_classifier.mdx +++ b/api_docs/kbn_repo_source_classifier.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-source-classifier title: "@kbn/repo-source-classifier" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-source-classifier plugin -date: 2023-09-25 +date: 2023-09-26 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 d6e4e4237cff5..fc7399a3ea66f 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-common'] --- import kbnReportingCommonObj from './kbn_reporting_common.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index f34844fc311aa..973ac3b76a18b 100644 --- a/api_docs/kbn_rison.mdx +++ b/api_docs/kbn_rison.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rison title: "@kbn/rison" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rison plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_rrule.mdx b/api_docs/kbn_rrule.mdx index 8ae853ee7e2f8..36ea0c9911914 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: 2023-09-25 +date: 2023-09-26 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 6d85dcea07a21..6c3bade371c46 100644 --- a/api_docs/kbn_rule_data_utils.mdx +++ b/api_docs/kbn_rule_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rule-data-utils title: "@kbn/rule-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rule-data-utils plugin -date: 2023-09-25 +date: 2023-09-26 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 cc68470fb7074..4579bddeb82c0 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-objects-settings'] --- import kbnSavedObjectsSettingsObj from './kbn_saved_objects_settings.devdocs.json'; diff --git a/api_docs/kbn_search_api_panels.mdx b/api_docs/kbn_search_api_panels.mdx index 4ebf980f79a2c..9711d47b79032 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: 2023-09-25 +date: 2023-09-26 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 5d1e79818fbf6..3d6c3b3dd1629 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-connectors'] --- import kbnSearchConnectorsObj from './kbn_search_connectors.devdocs.json'; diff --git a/api_docs/kbn_search_response_warnings.mdx b/api_docs/kbn_search_response_warnings.mdx index f90b75127bafd..720bb8c947728 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-response-warnings'] --- import kbnSearchResponseWarningsObj from './kbn_search_response_warnings.devdocs.json'; diff --git a/api_docs/kbn_security_solution_features.mdx b/api_docs/kbn_security_solution_features.mdx index dd6bac00eed15..3a7b9fb7b29bd 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: 2023-09-25 +date: 2023-09-26 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 5491a100b92a0..53d952c672703 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: 2023-09-25 +date: 2023-09-26 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 d8f757a466198..90e955c0398cf 100644 --- a/api_docs/kbn_security_solution_side_nav.mdx +++ b/api_docs/kbn_security_solution_side_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-side-nav title: "@kbn/security-solution-side-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-side-nav plugin -date: 2023-09-25 +date: 2023-09-26 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 441d2d7deec6d..74bc95eff08d9 100644 --- a/api_docs/kbn_security_solution_storybook_config.mdx +++ b/api_docs/kbn_security_solution_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-storybook-config title: "@kbn/security-solution-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-storybook-config plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-storybook-config'] --- import kbnSecuritySolutionStorybookConfigObj from './kbn_security_solution_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index 4a9fe5e16d8f4..4c9fd276f9248 100644 --- a/api_docs/kbn_securitysolution_autocomplete.mdx +++ b/api_docs/kbn_securitysolution_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-autocomplete title: "@kbn/securitysolution-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-autocomplete plugin -date: 2023-09-25 +date: 2023-09-26 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 06739a953d8e0..5877e8165caf6 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: 2023-09-25 +date: 2023-09-26 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 1b55f4c3a1b2c..056eb207c1d71 100644 --- a/api_docs/kbn_securitysolution_ecs.mdx +++ b/api_docs/kbn_securitysolution_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-ecs title: "@kbn/securitysolution-ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-ecs plugin -date: 2023-09-25 +date: 2023-09-26 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 4e877404e8766..7901693345840 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-es-utils plugin -date: 2023-09-25 +date: 2023-09-26 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 04c83082210b3..3df432c6d4b1b 100644 --- a/api_docs/kbn_securitysolution_exception_list_components.mdx +++ b/api_docs/kbn_securitysolution_exception_list_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-exception-list-components title: "@kbn/securitysolution-exception-list-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-exception-list-components plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-exception-list-components'] --- import kbnSecuritysolutionExceptionListComponentsObj from './kbn_securitysolution_exception_list_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_grouping.mdx b/api_docs/kbn_securitysolution_grouping.mdx index 33fad620f2896..e8e5890f5a424 100644 --- a/api_docs/kbn_securitysolution_grouping.mdx +++ b/api_docs/kbn_securitysolution_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-grouping title: "@kbn/securitysolution-grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-grouping plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-grouping'] --- import kbnSecuritysolutionGroupingObj from './kbn_securitysolution_grouping.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index 0bfe2641b5252..704206a5e81da 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-hook-utils plugin -date: 2023-09-25 +date: 2023-09-26 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 06ff94f2f2df1..f4ae78b50f948 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-alerting-types title: "@kbn/securitysolution-io-ts-alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin -date: 2023-09-25 +date: 2023-09-26 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 f44b472ee21c7..e24913c491538 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-list-types title: "@kbn/securitysolution-io-ts-list-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-list-types plugin -date: 2023-09-25 +date: 2023-09-26 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 4188e79322446..9b0af46ef301e 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-types plugin -date: 2023-09-25 +date: 2023-09-26 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 93000e4766bb0..36af13ef15e2e 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-utils plugin -date: 2023-09-25 +date: 2023-09-26 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 c212829becd91..9bccdca6b75ed 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-api plugin -date: 2023-09-25 +date: 2023-09-26 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 382577a5efb66..a9d1d761bce2d 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-constants plugin -date: 2023-09-25 +date: 2023-09-26 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 d65169c1c9390..a2aeb16601dac 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-hooks plugin -date: 2023-09-25 +date: 2023-09-26 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 0bcf950f45f42..307be0497b63d 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-utils plugin -date: 2023-09-25 +date: 2023-09-26 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 0f5d7f30b2d6c..c29cdd6f9a2f5 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-rules plugin -date: 2023-09-25 +date: 2023-09-26 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 18a139185788c..1fb6dfa5772c7 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-t-grid plugin -date: 2023-09-25 +date: 2023-09-26 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 07abe26b21359..a81b9227eb674 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-utils plugin -date: 2023-09-25 +date: 2023-09-26 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 9d29584068169..4736c892fecd6 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-http-tools plugin -date: 2023-09-25 +date: 2023-09-26 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 792ca2d60f366..fbe170ca6eaab 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_serverless_common_settings.mdx b/api_docs/kbn_serverless_common_settings.mdx index fad26aae0a9e1..4b15af859119c 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: 2023-09-25 +date: 2023-09-26 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 d373b4544a069..de67dd9e9c3b8 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: 2023-09-25 +date: 2023-09-26 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 d6f26b34962b4..e8eb38e131743 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: 2023-09-25 +date: 2023-09-26 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 ba2ddcb00c7dc..49ab83e831293 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: 2023-09-25 +date: 2023-09-26 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 78786e5912b76..e0102e31918e9 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: 2023-09-25 +date: 2023-09-26 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 071f541430312..f589fe3a43148 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: 2023-09-25 +date: 2023-09-26 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 32fcd923b17a5..e69c952cb8c06 100644 --- a/api_docs/kbn_shared_svg.mdx +++ b/api_docs/kbn_shared_svg.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-svg title: "@kbn/shared-svg" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-svg plugin -date: 2023-09-25 +date: 2023-09-26 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 9a631df590073..e385bb4a450f7 100644 --- a/api_docs/kbn_shared_ux_avatar_solution.mdx +++ b/api_docs/kbn_shared_ux_avatar_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-solution title: "@kbn/shared-ux-avatar-solution" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-solution plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-solution'] --- import kbnSharedUxAvatarSolutionObj from './kbn_shared_ux_avatar_solution.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx b/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx index 71fdec9587e9c..37949233d55c1 100644 --- a/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx +++ b/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-user-profile-components title: "@kbn/shared-ux-avatar-user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-user-profile-components plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-user-profile-components'] --- import kbnSharedUxAvatarUserProfileComponentsObj from './kbn_shared_ux_avatar_user_profile_components.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx index 271ceb24e9dfd..97d11af89f2ae 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen title: "@kbn/shared-ux-button-exit-full-screen" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen'] --- import kbnSharedUxButtonExitFullScreenObj from './kbn_shared_ux_button_exit_full_screen.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx index 6579ae10abdea..80c0df35833f3 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen-mocks title: "@kbn/shared-ux-button-exit-full-screen-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen-mocks plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen-mocks'] --- import kbnSharedUxButtonExitFullScreenMocksObj from './kbn_shared_ux_button_exit_full_screen_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.devdocs.json b/api_docs/kbn_shared_ux_button_toolbar.devdocs.json index c7dad0c8c07b9..612b861b36f38 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.devdocs.json +++ b/api_docs/kbn_shared_ux_button_toolbar.devdocs.json @@ -176,7 +176,7 @@ "label": "ToolbarButton", "description": [], "signature": [ - "({ label, type, iconSide, size, ...rest }: React.PropsWithChildren<", + "({ label, type, iconSide, size, isDisabled, ...rest }: React.PropsWithChildren<", { "pluginId": "@kbn/shared-ux-button-toolbar", "scope": "common", @@ -195,7 +195,7 @@ "id": "def-common.ToolbarButton.$1", "type": "CompoundType", "tags": [], - "label": "{\n label,\n type = 'empty',\n iconSide = 'left',\n size = 'm',\n ...rest\n}", + "label": "{\n label,\n type = 'empty',\n iconSide = 'left',\n size = 'm',\n isDisabled,\n ...rest\n}", "description": [], "signature": [ "React.PropsWithChildren<", @@ -227,7 +227,7 @@ "\nA button which opens a popover of additional actions within the toolbar." ], "signature": [ - "({ type, label, iconType, size, children, ...popover }: ", + "({ type, label, iconType, size, children, isDisabled, ...popover }: ", { "pluginId": "@kbn/shared-ux-button-toolbar", "scope": "common", @@ -246,7 +246,7 @@ "id": "def-common.ToolbarPopover.$1", "type": "CompoundType", "tags": [], - "label": "{\n type,\n label,\n iconType,\n size = 'm',\n children,\n ...popover\n}", + "label": "{\n type,\n label,\n iconType,\n size = 'm',\n children,\n isDisabled,\n ...popover\n}", "description": [], "signature": [ { @@ -450,7 +450,7 @@ }, " extends Pick<", "EuiButtonPropsForButton", - ", \"onClick\" | \"data-test-subj\" | \"iconType\" | \"size\" | \"iconSide\">" + ", \"onClick\" | \"data-test-subj\" | \"isDisabled\" | \"iconType\" | \"size\" | \"iconSide\">" ], "path": "packages/shared-ux/button_toolbar/src/buttons/toolbar_button/toolbar_button.tsx", "deprecated": false, @@ -525,7 +525,7 @@ "label": "Props", "description": [], "signature": [ - "{ onClick?: React.MouseEventHandler | undefined; 'data-test-subj'?: string | undefined; size?: \"m\" | \"s\" | undefined; iconSide?: ", + "{ onClick?: React.MouseEventHandler | undefined; 'data-test-subj'?: string | undefined; isDisabled?: boolean | undefined; size?: \"m\" | \"s\" | undefined; iconSide?: ", "ButtonContentIconSide", "; }" ], @@ -569,7 +569,7 @@ "section": "def-common.Props", "text": "Props" }, - "> | (({ type, label, iconType, size, children, ...popover }: ", + "> | (({ type, label, iconType, size, children, isDisabled, ...popover }: ", { "pluginId": "@kbn/shared-ux-button-toolbar", "scope": "common", diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index 67467d7465aca..5da0cc1bc0c60 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-toolbar plugin -date: 2023-09-25 +date: 2023-09-26 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 d8ba221beb0b6..476f5f18dafd0 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data title: "@kbn/shared-ux-card-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data plugin -date: 2023-09-25 +date: 2023-09-26 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 e9ded083fa890..72aa8e0e21208 100644 --- a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data-mocks title: "@kbn/shared-ux-card-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 36ea7df717cb8..65ed3565e0465 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: 2023-09-25 +date: 2023-09-26 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_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index 88224c82e199e..658a1dbe91557 100644 --- a/api_docs/kbn_shared_ux_file_context.mdx +++ b/api_docs/kbn_shared_ux_file_context.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-context title: "@kbn/shared-ux-file-context" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-context plugin -date: 2023-09-25 +date: 2023-09-26 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 50bd414ea40b0..bcf101c671ca4 100644 --- a/api_docs/kbn_shared_ux_file_image.mdx +++ b/api_docs/kbn_shared_ux_file_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image title: "@kbn/shared-ux-file-image" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image plugin -date: 2023-09-25 +date: 2023-09-26 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 e75dafb426bec..ed66d0331c888 100644 --- a/api_docs/kbn_shared_ux_file_image_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_image_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image-mocks title: "@kbn/shared-ux-file-image-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 40c537aba7b4d..a74922902f315 100644 --- a/api_docs/kbn_shared_ux_file_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-mocks title: "@kbn/shared-ux-file-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 aacf200fcf4a8..b03ccf59eef5d 100644 --- a/api_docs/kbn_shared_ux_file_picker.mdx +++ b/api_docs/kbn_shared_ux_file_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-picker title: "@kbn/shared-ux-file-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-picker plugin -date: 2023-09-25 +date: 2023-09-26 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 5ed875f5a62f7..2bcca3b05366e 100644 --- a/api_docs/kbn_shared_ux_file_types.mdx +++ b/api_docs/kbn_shared_ux_file_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-types title: "@kbn/shared-ux-file-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-types plugin -date: 2023-09-25 +date: 2023-09-26 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 411ecb70ef47d..2c6a16374de12 100644 --- a/api_docs/kbn_shared_ux_file_upload.mdx +++ b/api_docs/kbn_shared_ux_file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-upload title: "@kbn/shared-ux-file-upload" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-upload plugin -date: 2023-09-25 +date: 2023-09-26 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 32bf1d99be571..a5415ec9b6453 100644 --- a/api_docs/kbn_shared_ux_file_util.mdx +++ b/api_docs/kbn_shared_ux_file_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-util title: "@kbn/shared-ux-file-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-util plugin -date: 2023-09-25 +date: 2023-09-26 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 e2a54169e14bb..843da95efe757 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app title: "@kbn/shared-ux-link-redirect-app" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app plugin -date: 2023-09-25 +date: 2023-09-26 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 3420d3cc9c0ee..5cb1f502ef67b 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app-mocks title: "@kbn/shared-ux-link-redirect-app-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 f9bec4c5c3117..af7fa58f27fc5 100644 --- a/api_docs/kbn_shared_ux_markdown.mdx +++ b/api_docs/kbn_shared_ux_markdown.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown title: "@kbn/shared-ux-markdown" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown plugin -date: 2023-09-25 +date: 2023-09-26 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 030f61acf6948..85cb82f82d02e 100644 --- a/api_docs/kbn_shared_ux_markdown_mocks.mdx +++ b/api_docs/kbn_shared_ux_markdown_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown-mocks title: "@kbn/shared-ux-markdown-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 9306d1e357d48..83522bfac5e48 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data title: "@kbn/shared-ux-page-analytics-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data plugin -date: 2023-09-25 +date: 2023-09-26 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 49cd5ffa47422..54b092c36805d 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data-mocks title: "@kbn/shared-ux-page-analytics-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 5f1ee64b5911f..926c9fc114f5d 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data title: "@kbn/shared-ux-page-kibana-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data plugin -date: 2023-09-25 +date: 2023-09-26 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 007b4ff76e63f..90730706d3392 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data-mocks title: "@kbn/shared-ux-page-kibana-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 6235595b793a3..7084c7474d7d8 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template title: "@kbn/shared-ux-page-kibana-template" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template plugin -date: 2023-09-25 +date: 2023-09-26 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 c9c60681c8e6c..0c1b2a9dc76e3 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template-mocks title: "@kbn/shared-ux-page-kibana-template-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 d46851bdd71c2..cbb042a03d20d 100644 --- a/api_docs/kbn_shared_ux_page_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data title: "@kbn/shared-ux-page-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data plugin -date: 2023-09-25 +date: 2023-09-26 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 95c352d2c50a9..c5036666f90a2 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config title: "@kbn/shared-ux-page-no-data-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config plugin -date: 2023-09-25 +date: 2023-09-26 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 66ca7436ee8f3..5c1f54e51a457 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config-mocks title: "@kbn/shared-ux-page-no-data-config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 2417eb0bda622..0dff4a89ab264 100644 --- a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-mocks title: "@kbn/shared-ux-page-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 e13dee86891a6..e95c3324ca75b 100644 --- a/api_docs/kbn_shared_ux_page_solution_nav.mdx +++ b/api_docs/kbn_shared_ux_page_solution_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-solution-nav title: "@kbn/shared-ux-page-solution-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-solution-nav plugin -date: 2023-09-25 +date: 2023-09-26 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.devdocs.json b/api_docs/kbn_shared_ux_prompt_no_data_views.devdocs.json index 241bf46504f01..ce2b65c612ad3 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.devdocs.json +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.devdocs.json @@ -241,7 +241,7 @@ "The background color of the prompt; defaults to `plain`." ], "signature": [ - "\"warning\" | \"success\" | \"subdued\" | \"primary\" | \"accent\" | \"danger\" | \"transparent\" | \"plain\" | undefined" + "\"warning\" | \"success\" | \"subdued\" | \"primary\" | \"accent\" | \"danger\" | \"plain\" | \"transparent\" | undefined" ], "path": "packages/shared-ux/prompt/no_data_views/types/index.d.ts", "deprecated": false, 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 8d04826f4fb12..6143dd8dd5a60 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views title: "@kbn/shared-ux-prompt-no-data-views" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views plugin -date: 2023-09-25 +date: 2023-09-26 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 c5927aa75edd9..86b14b43344ee 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views-mocks title: "@kbn/shared-ux-prompt-no-data-views-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 c78b891291bf0..f54c6b45d677a 100644 --- a/api_docs/kbn_shared_ux_prompt_not_found.mdx +++ b/api_docs/kbn_shared_ux_prompt_not_found.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-not-found title: "@kbn/shared-ux-prompt-not-found" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-not-found plugin -date: 2023-09-25 +date: 2023-09-26 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 35b2a26610cbc..58b331aef29e0 100644 --- a/api_docs/kbn_shared_ux_router.mdx +++ b/api_docs/kbn_shared_ux_router.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router title: "@kbn/shared-ux-router" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router plugin -date: 2023-09-25 +date: 2023-09-26 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 954f26c3d143c..927af6b280e90 100644 --- a/api_docs/kbn_shared_ux_router_mocks.mdx +++ b/api_docs/kbn_shared_ux_router_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router-mocks title: "@kbn/shared-ux-router-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router-mocks plugin -date: 2023-09-25 +date: 2023-09-26 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 5957345b21b31..cff8f6bdce99e 100644 --- a/api_docs/kbn_shared_ux_storybook_config.mdx +++ b/api_docs/kbn_shared_ux_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-config title: "@kbn/shared-ux-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-config plugin -date: 2023-09-25 +date: 2023-09-26 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 0ecd6e2c5dda3..673bf477f0aa3 100644 --- a/api_docs/kbn_shared_ux_storybook_mock.mdx +++ b/api_docs/kbn_shared_ux_storybook_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-mock title: "@kbn/shared-ux-storybook-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-mock plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-mock'] --- import kbnSharedUxStorybookMockObj from './kbn_shared_ux_storybook_mock.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index 6754b62d97334..f015df67f02f2 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-utility plugin -date: 2023-09-25 +date: 2023-09-26 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 43593f0fccb25..6696a39762379 100644 --- a/api_docs/kbn_slo_schema.mdx +++ b/api_docs/kbn_slo_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-slo-schema title: "@kbn/slo-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/slo-schema plugin -date: 2023-09-25 +date: 2023-09-26 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 53c388e42aae3..3e19ef1f56218 100644 --- a/api_docs/kbn_some_dev_log.mdx +++ b/api_docs/kbn_some_dev_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-some-dev-log title: "@kbn/some-dev-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/some-dev-log plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index 67e81a160f3c8..d2be8a25605de 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/std plugin -date: 2023-09-25 +date: 2023-09-26 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 a3ce537041e5f..8068a5438d3ad 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/stdio-dev-helpers plugin -date: 2023-09-25 +date: 2023-09-26 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 84ca7e10eb8c5..b0c6496e11050 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/storybook plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_subscription_tracking.mdx b/api_docs/kbn_subscription_tracking.mdx index fe0bb888f443b..2ea59be675b21 100644 --- a/api_docs/kbn_subscription_tracking.mdx +++ b/api_docs/kbn_subscription_tracking.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-subscription-tracking title: "@kbn/subscription-tracking" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/subscription-tracking plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/subscription-tracking'] --- import kbnSubscriptionTrackingObj from './kbn_subscription_tracking.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index 3cc441b24deff..a5e88c3cc7c11 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/telemetry-tools plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] --- import kbnTelemetryToolsObj from './kbn_telemetry_tools.devdocs.json'; diff --git a/api_docs/kbn_test.devdocs.json b/api_docs/kbn_test.devdocs.json index 5fdb6cc0e3de2..ca43d8708297a 100644 --- a/api_docs/kbn_test.devdocs.json +++ b/api_docs/kbn_test.devdocs.json @@ -2719,7 +2719,7 @@ "section": "def-common.EsVersion", "text": "EsVersion" }, - "; bail: boolean; dryRun: boolean; updateBaselines: boolean; updateSnapshots: boolean; logsDir: string | undefined; esFrom: \"source\" | \"snapshot\" | \"serverless\" | undefined; installDir: string | undefined; grep: string | undefined; suiteTags: { include: string[]; exclude: string[]; }; suiteFilters: { include: string[]; exclude: string[]; }; }) => Promise" + "; bail: boolean; dryRun: boolean; updateBaselines: boolean; updateSnapshots: boolean; logsDir: string | undefined; esFrom: \"source\" | \"snapshot\" | \"serverless\" | undefined; esServerlessImage: string | undefined; installDir: string | undefined; grep: string | undefined; suiteTags: { include: string[]; exclude: string[]; }; suiteFilters: { include: string[]; exclude: string[]; }; }) => Promise" ], "path": "packages/kbn-test/src/functional_tests/run_tests/run_tests.ts", "deprecated": false, @@ -2762,7 +2762,7 @@ "section": "def-common.EsVersion", "text": "EsVersion" }, - "; bail: boolean; dryRun: boolean; updateBaselines: boolean; updateSnapshots: boolean; logsDir: string | undefined; esFrom: \"source\" | \"snapshot\" | \"serverless\" | undefined; installDir: string | undefined; grep: string | undefined; suiteTags: { include: string[]; exclude: string[]; }; suiteFilters: { include: string[]; exclude: string[]; }; }" + "; bail: boolean; dryRun: boolean; updateBaselines: boolean; updateSnapshots: boolean; logsDir: string | undefined; esFrom: \"source\" | \"snapshot\" | \"serverless\" | undefined; esServerlessImage: string | undefined; installDir: string | undefined; grep: string | undefined; suiteTags: { include: string[]; exclude: string[]; }; suiteFilters: { include: string[]; exclude: string[]; }; }" ], "path": "packages/kbn-test/src/functional_tests/run_tests/run_tests.ts", "deprecated": false, @@ -3112,6 +3112,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.CreateTestEsClusterOptions.esServerlessOptions", + "type": "Object", + "tags": [], + "label": "esServerlessOptions", + "description": [], + "signature": [ + "{ image?: string | undefined; tag?: string | undefined; } | undefined" + ], + "path": "packages/kbn-test/src/es/test_es_cluster.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/test", "id": "def-common.CreateTestEsClusterOptions.esJavaOpts", diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index 6496939d9eedc..0fe13e901c073 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kiban | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 289 | 4 | 242 | 12 | +| 290 | 4 | 243 | 12 | ## Common diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index b34d60d6b550d..8a8a3cd816bf8 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-jest-helpers plugin -date: 2023-09-25 +date: 2023-09-26 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 ef1373e4e04a3..76b43765a11de 100644 --- a/api_docs/kbn_test_subj_selector.mdx +++ b/api_docs/kbn_test_subj_selector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-subj-selector title: "@kbn/test-subj-selector" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-subj-selector plugin -date: 2023-09-25 +date: 2023-09-26 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 e645d678a63ea..7cf0c03435829 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/text-based-editor'] --- import kbnTextBasedEditorObj from './kbn_text_based_editor.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index 1d2a423a9e246..4988da7e7c52e 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/tooling-log plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_ts_projects.mdx b/api_docs/kbn_ts_projects.mdx index decbd00deb337..d4926ccf78095 100644 --- a/api_docs/kbn_ts_projects.mdx +++ b/api_docs/kbn_ts_projects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ts-projects title: "@kbn/ts-projects" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ts-projects plugin -date: 2023-09-25 +date: 2023-09-26 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 2537e0dc1b876..194d913445df0 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/typed-react-router-config plugin -date: 2023-09-25 +date: 2023-09-26 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 d993114d9030e..5a5605d090214 100644 --- a/api_docs/kbn_ui_actions_browser.mdx +++ b/api_docs/kbn_ui_actions_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-actions-browser title: "@kbn/ui-actions-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-actions-browser plugin -date: 2023-09-25 +date: 2023-09-26 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 038fc61ec1777..1d0a8d3a08a83 100644 --- a/api_docs/kbn_ui_shared_deps_src.mdx +++ b/api_docs/kbn_ui_shared_deps_src.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-shared-deps-src title: "@kbn/ui-shared-deps-src" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-shared-deps-src plugin -date: 2023-09-25 +date: 2023-09-26 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 e463b7fe240d5..d05ea8cb8136a 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-theme plugin -date: 2023-09-25 +date: 2023-09-26 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 3d0d1c5c4f2d1..e58baed74563f 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: 2023-09-25 +date: 2023-09-26 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 a5fdd13cb1cd6..b9d36b0b3e3e9 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: 2023-09-25 +date: 2023-09-26 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 e05758c82150a..c9b1ffbe83185 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-field-list'] --- import kbnUnifiedFieldListObj from './kbn_unified_field_list.devdocs.json'; diff --git a/api_docs/kbn_url_state.mdx b/api_docs/kbn_url_state.mdx index 2ce6f5decf7b2..72d2e88165371 100644 --- a/api_docs/kbn_url_state.mdx +++ b/api_docs/kbn_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-url-state title: "@kbn/url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/url-state plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/url-state'] --- import kbnUrlStateObj from './kbn_url_state.devdocs.json'; diff --git a/api_docs/kbn_use_tracked_promise.mdx b/api_docs/kbn_use_tracked_promise.mdx index 48d0dd44260c3..46a24601095a9 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: 2023-09-25 +date: 2023-09-26 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 062a1d9c6a56b..a37a7120f0012 100644 --- a/api_docs/kbn_user_profile_components.mdx +++ b/api_docs/kbn_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-user-profile-components title: "@kbn/user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/user-profile-components plugin -date: 2023-09-25 +date: 2023-09-26 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 1a13b648d4c67..76c7071cea896 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types plugin -date: 2023-09-25 +date: 2023-09-26 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 f0a30cbc64ba1..7554c601f4451 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types-jest plugin -date: 2023-09-25 +date: 2023-09-26 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 4cbcfbedb9188..e5e5d58fc6ebc 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utils plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_visualization_ui_components.devdocs.json b/api_docs/kbn_visualization_ui_components.devdocs.json index 0b9da0c5161ea..c33aaf04d4bed 100644 --- a/api_docs/kbn_visualization_ui_components.devdocs.json +++ b/api_docs/kbn_visualization_ui_components.devdocs.json @@ -390,7 +390,7 @@ "label": "DragDropBuckets", "description": [], "signature": [ - "({\n items,\n onDragStart,\n onDragEnd,\n droppableId,\n children,\n bgColor,\n}: { items: T[]; droppableId: string; children: React.ReactElement>[]; onDragStart?: (() => void) | undefined; onDragEnd?: ((items: T[]) => void) | undefined; bgColor?: \"warning\" | \"success\" | \"subdued\" | \"primary\" | \"accent\" | \"danger\" | \"transparent\" | \"plain\" | undefined; }) => JSX.Element" + "({\n items,\n onDragStart,\n onDragEnd,\n droppableId,\n children,\n bgColor,\n}: { items: T[]; droppableId: string; children: React.ReactElement>[]; onDragStart?: (() => void) | undefined; onDragEnd?: ((items: T[]) => void) | undefined; bgColor?: \"warning\" | \"success\" | \"subdued\" | \"primary\" | \"accent\" | \"danger\" | \"plain\" | \"transparent\" | undefined; }) => JSX.Element" ], "path": "packages/kbn-visualization-ui-components/components/drag_drop_bucket/buckets.tsx", "deprecated": false, @@ -502,7 +502,7 @@ "label": "bgColor", "description": [], "signature": [ - "\"warning\" | \"success\" | \"subdued\" | \"primary\" | \"accent\" | \"danger\" | \"transparent\" | \"plain\" | undefined" + "\"warning\" | \"success\" | \"subdued\" | \"primary\" | \"accent\" | \"danger\" | \"plain\" | \"transparent\" | undefined" ], "path": "packages/kbn-visualization-ui-components/components/drag_drop_bucket/buckets.tsx", "deprecated": false, diff --git a/api_docs/kbn_visualization_ui_components.mdx b/api_docs/kbn_visualization_ui_components.mdx index 1c531f6930ab8..bccdfdf3ee83d 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-ui-components'] --- import kbnVisualizationUiComponentsObj from './kbn_visualization_ui_components.devdocs.json'; diff --git a/api_docs/kbn_xstate_utils.mdx b/api_docs/kbn_xstate_utils.mdx index 79d878c81029a..6d5e19f2e26b1 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: 2023-09-25 +date: 2023-09-26 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 ea2dba80cb34e..29b6a1a2dcb96 100644 --- a/api_docs/kbn_yarn_lock_validator.mdx +++ b/api_docs/kbn_yarn_lock_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-yarn-lock-validator title: "@kbn/yarn-lock-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/yarn-lock-validator plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index bdedbca270552..ad97e1b790831 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaOverview plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.devdocs.json b/api_docs/kibana_react.devdocs.json index 211c5113537ad..9ab84b03192f2 100644 --- a/api_docs/kibana_react.devdocs.json +++ b/api_docs/kibana_react.devdocs.json @@ -528,95 +528,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "kibanaReact", - "id": "def-public.KibanaPageTemplate", - "type": "Function", - "tags": [ - "deprecated" - ], - "label": "KibanaPageTemplate", - "description": [], - "signature": [ - "({ template, className, children, solutionNav, noDataConfig, ...rest }: React.PropsWithChildren<", - { - "pluginId": "kibanaReact", - "scope": "public", - "docId": "kibKibanaReactPluginApi", - "section": "def-public.KibanaPageTemplateProps", - "text": "KibanaPageTemplateProps" - }, - ">) => JSX.Element" - ], - "path": "src/plugins/kibana_react/public/page_template/page_template.tsx", - "deprecated": true, - "trackAdoption": false, - "references": [ - { - "plugin": "home", - "path": "src/plugins/home/public/application/components/tutorial_directory.js" - }, - { - "plugin": "home", - "path": "src/plugins/home/public/application/components/tutorial_directory.js" - }, - { - "plugin": "home", - "path": "src/plugins/home/public/application/components/tutorial_directory.js" - }, - { - "plugin": "home", - "path": "src/plugins/home/public/application/components/tutorial/tutorial.js" - }, - { - "plugin": "home", - "path": "src/plugins/home/public/application/components/tutorial/tutorial.js" - }, - { - "plugin": "home", - "path": "src/plugins/home/public/application/components/tutorial/tutorial.js" - }, - { - "plugin": "home", - "path": "src/plugins/home/public/application/components/tutorial/tutorial.js" - }, - { - "plugin": "osquery", - "path": "x-pack/plugins/osquery/public/components/empty_state.tsx" - }, - { - "plugin": "osquery", - "path": "x-pack/plugins/osquery/public/components/empty_state.tsx" - } - ], - "children": [ - { - "parentPluginId": "kibanaReact", - "id": "def-public.KibanaPageTemplate.$1", - "type": "CompoundType", - "tags": [], - "label": "{\n template,\n className,\n children,\n solutionNav,\n noDataConfig,\n ...rest\n}", - "description": [], - "signature": [ - "React.PropsWithChildren<", - { - "pluginId": "kibanaReact", - "scope": "public", - "docId": "kibKibanaReactPluginApi", - "section": "def-public.KibanaPageTemplateProps", - "text": "KibanaPageTemplateProps" - }, - ">" - ], - "path": "src/plugins/kibana_react/public/page_template/page_template.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, { "parentPluginId": "kibanaReact", "id": "def-public.KibanaPageTemplateSolutionNavAvatar", @@ -5565,50 +5476,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "kibanaReact", - "id": "def-public.KibanaPageTemplateProps", - "type": "Type", - "tags": [ - "deprecated" - ], - "label": "KibanaPageTemplateProps", - "description": [ - "\nA thin wrapper around EuiPageTemplate with a few Kibana specific additions" - ], - "signature": [ - "Omit<", - "EuiPageProps", - ", \"paddingSize\"> & { template?: \"default\" | \"empty\" | \"centeredBody\" | \"centeredContent\" | undefined; paddingSize?: \"m\" | \"none\" | \"s\" | \"l\" | undefined; pageSideBar?: React.ReactNode; pageSideBarProps?: ", - "EuiPageSideBarProps_Deprecated", - " | undefined; pageHeader?: ", - "EuiPageHeaderProps", - " | undefined; pageBodyProps?: any; pageContentProps?: ", - "EuiPageContentProps", - " | undefined; pageContentBodyProps?: ", - "EuiPageContentBodyProps", - " | undefined; bottomBar?: React.ReactNode; bottomBarProps?: ", - "EuiBottomBarProps", - " | undefined; fullHeight?: boolean | \"noscroll\" | undefined; minHeight?: ", - "Property", - ".MinHeight | undefined; } & { isEmptyState?: boolean | undefined; solutionNav?: ", - "KibanaPageTemplateSolutionNavProps", - " | undefined; noDataConfig?: ", - { - "pluginId": "kibanaReact", - "scope": "public", - "docId": "kibKibanaReactPluginApi", - "section": "def-public.NoDataPageProps", - "text": "NoDataPageProps" - }, - " | undefined; }" - ], - "path": "src/plugins/kibana_react/public/page_template/page_template.tsx", - "deprecated": true, - "trackAdoption": false, - "references": [], - "initialIsOpen": false - }, { "parentPluginId": "kibanaReact", "id": "def-public.KibanaServices", @@ -5875,21 +5742,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "kibanaReact", - "id": "def-public.NO_DATA_PAGE_MAX_WIDTH", - "type": "number", - "tags": [], - "label": "NO_DATA_PAGE_MAX_WIDTH", - "description": [], - "signature": [ - "950" - ], - "path": "src/plugins/kibana_react/public/page_template/util/constants.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "kibanaReact", "id": "def-public.NO_DATA_RECOMMENDED", @@ -6083,86 +5935,6 @@ "trackAdoption": false, "references": [], "initialIsOpen": false - }, - { - "parentPluginId": "kibanaReact", - "id": "def-public.NO_DATA_PAGE_TEMPLATE_PROPS", - "type": "Object", - "tags": [], - "label": "NO_DATA_PAGE_TEMPLATE_PROPS", - "description": [], - "path": "src/plugins/kibana_react/public/page_template/util/constants.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "kibanaReact", - "id": "def-public.NO_DATA_PAGE_TEMPLATE_PROPS.restrictWidth", - "type": "number", - "tags": [], - "label": "restrictWidth", - "description": [], - "path": "src/plugins/kibana_react/public/page_template/util/constants.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "kibanaReact", - "id": "def-public.NO_DATA_PAGE_TEMPLATE_PROPS.template", - "type": "string", - "tags": [], - "label": "template", - "description": [], - "signature": [ - "\"centeredBody\"" - ], - "path": "src/plugins/kibana_react/public/page_template/util/constants.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "kibanaReact", - "id": "def-public.NO_DATA_PAGE_TEMPLATE_PROPS.pageContentProps", - "type": "Object", - "tags": [], - "label": "pageContentProps", - "description": [], - "path": "src/plugins/kibana_react/public/page_template/util/constants.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "kibanaReact", - "id": "def-public.NO_DATA_PAGE_TEMPLATE_PROPS.pageContentProps.hasShadow", - "type": "boolean", - "tags": [], - "label": "hasShadow", - "description": [], - "signature": [ - "false" - ], - "path": "src/plugins/kibana_react/public/page_template/util/constants.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "kibanaReact", - "id": "def-public.NO_DATA_PAGE_TEMPLATE_PROPS.pageContentProps.color", - "type": "string", - "tags": [], - "label": "color", - "description": [], - "signature": [ - "\"transparent\"" - ], - "path": "src/plugins/kibana_react/public/page_template/util/constants.ts", - "deprecated": false, - "trackAdoption": false - } - ] - } - ], - "initialIsOpen": false } ] }, diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index e6e6d1c79f399..6eeeeb13e6137 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaReact plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaReact'] --- import kibanaReactObj from './kibana_react.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 | |-------------------|-----------|------------------------|-----------------| -| 186 | 0 | 147 | 5 | +| 176 | 0 | 138 | 4 | ## Client diff --git a/api_docs/kibana_utils.mdx b/api_docs/kibana_utils.mdx index 7b8bd82e4b379..feb9e32872e7b 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaUtils plugin -date: 2023-09-25 +date: 2023-09-26 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 56e303a369da9..eccfadbdaf9f2 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the kubernetesSecurity plugin -date: 2023-09-25 +date: 2023-09-26 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 d7c5ee36cf544..b5f54ff609de0 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github description: API docs for the lens plugin -date: 2023-09-25 +date: 2023-09-26 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 b75acced2933b..636a2313f6a2a 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseApiGuard plugin -date: 2023-09-25 +date: 2023-09-26 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 6be041ab64094..b9ff4a017eb87 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseManagement plugin -date: 2023-09-25 +date: 2023-09-26 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 34e62db8ad621..4f63fe8ba1dec 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github description: API docs for the licensing plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 5d4a9833c3f67..f8646a9bb9e07 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github description: API docs for the lists plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/log_explorer.mdx b/api_docs/log_explorer.mdx index 4458359118c0c..a15d894df5f2e 100644 --- a/api_docs/log_explorer.mdx +++ b/api_docs/log_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logExplorer title: "logExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the logExplorer plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logExplorer'] --- import logExplorerObj from './log_explorer.devdocs.json'; diff --git a/api_docs/logs_shared.mdx b/api_docs/logs_shared.mdx index 53896af7ca3ae..5ceb15dcff473 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: 2023-09-25 +date: 2023-09-26 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 dec665821074d..f80ac97b8542c 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github description: API docs for the management plugin -date: 2023-09-25 +date: 2023-09-26 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 f786984d06688..ab28fa9dc9afb 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github description: API docs for the maps plugin -date: 2023-09-25 +date: 2023-09-26 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 4080f96be52d9..c194c05150afa 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github description: API docs for the mapsEms plugin -date: 2023-09-25 +date: 2023-09-26 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 43e2f158d86d2..8db11685ae7d4 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'metricsDataAccess'] --- import metricsDataAccessObj from './metrics_data_access.devdocs.json'; diff --git a/api_docs/ml.devdocs.json b/api_docs/ml.devdocs.json index c45d27e8fd7df..a4e074b85b960 100644 --- a/api_docs/ml.devdocs.json +++ b/api_docs/ml.devdocs.json @@ -185,6 +185,8 @@ "signature": [ "(ml: { locator: ", "MlLocator", + " | undefined; elasticModels: ", + "ElasticModels", " | undefined; } | undefined, basePath: string | undefined, params: ", "MlLocatorParams", ", dependencies?: React.DependencyList | undefined) => string" @@ -203,6 +205,8 @@ "signature": [ "{ locator: ", "MlLocator", + " | undefined; elasticModels: ", + "ElasticModels", " | undefined; } | undefined" ], "path": "x-pack/plugins/ml/public/locator/use_ml_href.ts", @@ -1033,6 +1037,24 @@ "initialIsOpen": false } ], + "setup": { + "parentPluginId": "ml", + "id": "def-public.MlPluginSetup", + "type": "Type", + "tags": [], + "label": "MlPluginSetup", + "description": [], + "signature": [ + "{ locator: ", + "MlLocator", + " | undefined; }" + ], + "path": "x-pack/plugins/ml/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "lifecycle": "setup", + "initialIsOpen": true + }, "start": { "parentPluginId": "ml", "id": "def-public.MlPluginStart", @@ -1043,6 +1065,8 @@ "signature": [ "{ locator: ", "MlLocator", + " | undefined; elasticModels: ", + "ElasticModels", " | undefined; }" ], "path": "x-pack/plugins/ml/public/plugin.ts", diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index c44412e6d97dd..9eb82115f70ea 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github description: API docs for the ml plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; @@ -21,10 +21,13 @@ Contact [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 150 | 3 | 64 | 32 | +| 150 | 3 | 64 | 33 | ## Client +### Setup + + ### Start diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index 88ae35bb39820..d467c48032470 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoring plugin -date: 2023-09-25 +date: 2023-09-26 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 8858bcb67fa2a..f371df08341ca 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoringCollection plugin -date: 2023-09-25 +date: 2023-09-26 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 d6f70e87f6b38..d4d7ca7074123 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the navigation plugin -date: 2023-09-25 +date: 2023-09-26 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 da3b147d0c5cd..5121b52917317 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github description: API docs for the newsfeed plugin -date: 2023-09-25 +date: 2023-09-26 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 9b8982d43d4d4..01dad688b62e2 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: 2023-09-25 +date: 2023-09-26 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 6af21d9d02bbf..5d6253604f38f 100644 --- a/api_docs/notifications.mdx +++ b/api_docs/notifications.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/notifications title: "notifications" image: https://source.unsplash.com/400x175/?github description: API docs for the notifications plugin -date: 2023-09-25 +date: 2023-09-26 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 26b0dfe884c06..67c8970bcd528 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observability title: "observability" image: https://source.unsplash.com/400x175/?github description: API docs for the observability plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant.devdocs.json b/api_docs/observability_a_i_assistant.devdocs.json index 73a81e8571d20..a5c30ac27ef5d 100644 --- a/api_docs/observability_a_i_assistant.devdocs.json +++ b/api_docs/observability_a_i_assistant.devdocs.json @@ -452,6 +452,8 @@ "; \"POST /internal/observability_ai_assistant/functions/recall\": { endpoint: \"POST /internal/observability_ai_assistant/functions/recall\"; params?: ", "TypeC", "<{ body: ", + "IntersectionC", + "<[", "TypeC", "<{ queries: ", "ArrayC", @@ -467,7 +469,13 @@ "section": "def-common.NonEmptyStringBrand", "text": "NonEmptyStringBrand" }, - ">>; }>; }> | undefined; handler: ({}: ", + ">>; }>, ", + "PartialC", + "<{ contexts: ", + "ArrayC", + "<", + "StringC", + ">; }>]>; }> | undefined; handler: ({}: ", "ObservabilityAIAssistantRouteHandlerResources", " & { params: { body: { queries: ", "Branded", @@ -479,9 +487,9 @@ "section": "def-common.NonEmptyStringBrand", "text": "NonEmptyStringBrand" }, - ">[]; }; }; }) => Promise<{ entries: Pick<", - "KnowledgeBaseEntry", - ", \"id\" | \"text\">[]; }>; } & ", + ">[]; } & { contexts?: string[] | undefined; }; }; }) => Promise<{ entries: ", + "RecalledEntry", + "[]; }>; } & ", "ObservabilityAIAssistantRouteCreateOptions", "; \"POST /internal/observability_ai_assistant/functions/elasticsearch\": { endpoint: \"POST /internal/observability_ai_assistant/functions/elasticsearch\"; params?: ", "TypeC", @@ -666,8 +674,12 @@ ">; } & ", "ObservabilityAIAssistantRouteCreateOptions", "; \"POST /internal/observability_ai_assistant/chat\": { endpoint: \"POST /internal/observability_ai_assistant/chat\"; params?: ", + "IntersectionC", + "<[", "TypeC", "<{ body: ", + "IntersectionC", + "<[", "TypeC", "<{ messages: ", "ArrayC", @@ -701,7 +713,17 @@ "StringC", "; parameters: ", "AnyC", - "; }>>; }>; }> | undefined; handler: ({}: ", + "; }>>; }>, ", + "PartialC", + "<{ functionCall: ", + "StringC", + "; }>]>; }>, ", + "PartialC", + "<{ query: ", + "TypeC", + "<{ stream: ", + "Type", + "; }>; }>]> | undefined; handler: ({}: ", "ObservabilityAIAssistantRouteHandlerResources", " & { params: { body: { messages: ", { @@ -711,8 +733,10 @@ "section": "def-common.Message", "text": "Message" }, - "[]; connectorId: string; functions: { name: string; description: string; parameters: any; }[]; }; }; }) => Promise<", + "[]; connectorId: string; functions: { name: string; description: string; parameters: any; }[]; } & { functionCall?: string | undefined; }; } & { query?: { stream: boolean; } | undefined; }; }) => Promise<", "IncomingMessage", + " | ", + "CreateChatCompletionResponse", ">; } & ", "ObservabilityAIAssistantRouteCreateOptions", "; }[TEndpoint] extends { endpoint: any; params?: any; handler: ({}: any) => Promise; } & ", @@ -817,6 +841,8 @@ "; \"POST /internal/observability_ai_assistant/functions/recall\": { endpoint: \"POST /internal/observability_ai_assistant/functions/recall\"; params?: ", "TypeC", "<{ body: ", + "IntersectionC", + "<[", "TypeC", "<{ queries: ", "ArrayC", @@ -832,7 +858,13 @@ "section": "def-common.NonEmptyStringBrand", "text": "NonEmptyStringBrand" }, - ">>; }>; }> | undefined; handler: ({}: ", + ">>; }>, ", + "PartialC", + "<{ contexts: ", + "ArrayC", + "<", + "StringC", + ">; }>]>; }> | undefined; handler: ({}: ", "ObservabilityAIAssistantRouteHandlerResources", " & { params: { body: { queries: ", "Branded", @@ -844,9 +876,9 @@ "section": "def-common.NonEmptyStringBrand", "text": "NonEmptyStringBrand" }, - ">[]; }; }; }) => Promise<{ entries: Pick<", - "KnowledgeBaseEntry", - ", \"id\" | \"text\">[]; }>; } & ", + ">[]; } & { contexts?: string[] | undefined; }; }; }) => Promise<{ entries: ", + "RecalledEntry", + "[]; }>; } & ", "ObservabilityAIAssistantRouteCreateOptions", "; \"POST /internal/observability_ai_assistant/functions/elasticsearch\": { endpoint: \"POST /internal/observability_ai_assistant/functions/elasticsearch\"; params?: ", "TypeC", @@ -1031,8 +1063,12 @@ ">; } & ", "ObservabilityAIAssistantRouteCreateOptions", "; \"POST /internal/observability_ai_assistant/chat\": { endpoint: \"POST /internal/observability_ai_assistant/chat\"; params?: ", + "IntersectionC", + "<[", "TypeC", "<{ body: ", + "IntersectionC", + "<[", "TypeC", "<{ messages: ", "ArrayC", @@ -1066,7 +1102,17 @@ "StringC", "; parameters: ", "AnyC", - "; }>>; }>; }> | undefined; handler: ({}: ", + "; }>>; }>, ", + "PartialC", + "<{ functionCall: ", + "StringC", + "; }>]>; }>, ", + "PartialC", + "<{ query: ", + "TypeC", + "<{ stream: ", + "Type", + "; }>; }>]> | undefined; handler: ({}: ", "ObservabilityAIAssistantRouteHandlerResources", " & { params: { body: { messages: ", { @@ -1076,8 +1122,10 @@ "section": "def-common.Message", "text": "Message" }, - "[]; connectorId: string; functions: { name: string; description: string; parameters: any; }[]; }; }; }) => Promise<", + "[]; connectorId: string; functions: { name: string; description: string; parameters: any; }[]; } & { functionCall?: string | undefined; }; } & { query?: { stream: boolean; } | undefined; }; }) => Promise<", "IncomingMessage", + " | ", + "CreateChatCompletionResponse", ">; } & ", "ObservabilityAIAssistantRouteCreateOptions", "; }[TEndpoint] extends { endpoint: any; params?: infer TRouteParamsRT | undefined; handler: ({}: any) => Promise; } & ", @@ -1288,6 +1336,8 @@ "; \"POST /internal/observability_ai_assistant/functions/recall\": { endpoint: \"POST /internal/observability_ai_assistant/functions/recall\"; params?: ", "TypeC", "<{ body: ", + "IntersectionC", + "<[", "TypeC", "<{ queries: ", "ArrayC", @@ -1303,7 +1353,13 @@ "section": "def-common.NonEmptyStringBrand", "text": "NonEmptyStringBrand" }, - ">>; }>; }> | undefined; handler: ({}: ", + ">>; }>, ", + "PartialC", + "<{ contexts: ", + "ArrayC", + "<", + "StringC", + ">; }>]>; }> | undefined; handler: ({}: ", "ObservabilityAIAssistantRouteHandlerResources", " & { params: { body: { queries: ", "Branded", @@ -1315,9 +1371,9 @@ "section": "def-common.NonEmptyStringBrand", "text": "NonEmptyStringBrand" }, - ">[]; }; }; }) => Promise<{ entries: Pick<", - "KnowledgeBaseEntry", - ", \"id\" | \"text\">[]; }>; } & ", + ">[]; } & { contexts?: string[] | undefined; }; }; }) => Promise<{ entries: ", + "RecalledEntry", + "[]; }>; } & ", "ObservabilityAIAssistantRouteCreateOptions", "; \"POST /internal/observability_ai_assistant/functions/elasticsearch\": { endpoint: \"POST /internal/observability_ai_assistant/functions/elasticsearch\"; params?: ", "TypeC", @@ -1502,8 +1558,12 @@ ">; } & ", "ObservabilityAIAssistantRouteCreateOptions", "; \"POST /internal/observability_ai_assistant/chat\": { endpoint: \"POST /internal/observability_ai_assistant/chat\"; params?: ", + "IntersectionC", + "<[", "TypeC", "<{ body: ", + "IntersectionC", + "<[", "TypeC", "<{ messages: ", "ArrayC", @@ -1537,7 +1597,17 @@ "StringC", "; parameters: ", "AnyC", - "; }>>; }>; }> | undefined; handler: ({}: ", + "; }>>; }>, ", + "PartialC", + "<{ functionCall: ", + "StringC", + "; }>]>; }>, ", + "PartialC", + "<{ query: ", + "TypeC", + "<{ stream: ", + "Type", + "; }>; }>]> | undefined; handler: ({}: ", "ObservabilityAIAssistantRouteHandlerResources", " & { params: { body: { messages: ", { @@ -1547,8 +1617,10 @@ "section": "def-common.Message", "text": "Message" }, - "[]; connectorId: string; functions: { name: string; description: string; parameters: any; }[]; }; }; }) => Promise<", + "[]; connectorId: string; functions: { name: string; description: string; parameters: any; }[]; } & { functionCall?: string | undefined; }; } & { query?: { stream: boolean; } | undefined; }; }) => Promise<", "IncomingMessage", + " | ", + "CreateChatCompletionResponse", ">; } & ", "ObservabilityAIAssistantRouteCreateOptions", "; }" diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index c242ea33b84a3..b8584211bc96d 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistant'] --- import observabilityAIAssistantObj from './observability_a_i_assistant.devdocs.json'; diff --git a/api_docs/observability_log_explorer.mdx b/api_docs/observability_log_explorer.mdx index efbf8d8ef6964..c5361488c7433 100644 --- a/api_docs/observability_log_explorer.mdx +++ b/api_docs/observability_log_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityLogExplorer title: "observabilityLogExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityLogExplorer plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityLogExplorer'] --- import observabilityLogExplorerObj from './observability_log_explorer.devdocs.json'; diff --git a/api_docs/observability_onboarding.mdx b/api_docs/observability_onboarding.mdx index ebea39421d24e..065c3bc1b4521 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityOnboarding'] --- import observabilityOnboardingObj from './observability_onboarding.devdocs.json'; diff --git a/api_docs/observability_shared.devdocs.json b/api_docs/observability_shared.devdocs.json index 6fcdc031dedc8..adb4f71475fbc 100644 --- a/api_docs/observability_shared.devdocs.json +++ b/api_docs/observability_shared.devdocs.json @@ -2745,6 +2745,51 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.ProfilingLocators", + "type": "Type", + "tags": [], + "label": "ProfilingLocators", + "description": [], + "signature": [ + "{ flamegraphLocator: ", + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.LocatorPublic", + "text": "LocatorPublic" + }, + "<", + "FlamegraphLocatorParams", + ">; topNFunctionsLocator: ", + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.LocatorPublic", + "text": "LocatorPublic" + }, + "<", + "TopNFunctionsLocatorParams", + ">; stacktracesLocator: ", + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.LocatorPublic", + "text": "LocatorPublic" + }, + "<", + "StacktracesLocatorParams", + ">; }" + ], + "path": "x-pack/plugins/observability_shared/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "observabilityShared", "id": "def-public.SectionLinkProps", diff --git a/api_docs/observability_shared.mdx b/api_docs/observability_shared.mdx index 734af78596c5a..70af23bfc6961 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityShared'] --- import observabilitySharedObj from './observability_shared.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/observability-ui](https://github.com/orgs/elastic/teams/observ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 286 | 1 | 283 | 15 | +| 287 | 1 | 284 | 15 | ## Client diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 3858846b4cc04..a6aeb1b261a39 100644 --- a/api_docs/osquery.mdx +++ b/api_docs/osquery.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/osquery title: "osquery" image: https://source.unsplash.com/400x175/?github description: API docs for the osquery plugin -date: 2023-09-25 +date: 2023-09-26 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 6796e6142c2df..da7ed9bf51767 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: 2023-09-25 +date: 2023-09-26 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 e581d99af5289..2854a4c0cc913 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -7,7 +7,7 @@ id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory description: Directory of public APIs available through plugins or packages. -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -15,13 +15,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Count | Plugins or Packages with a
    public API | Number of teams | |--------------|----------|------------------------| -| 691 | 583 | 42 | +| 692 | 584 | 42 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 74970 | 223 | 63945 | 1537 | +| 74981 | 223 | 63957 | 1538 | ## Plugin Directory @@ -71,7 +71,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds embeddables service to Kibana | 534 | 1 | 434 | 7 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Extends embeddable plugin with more functionality | 14 | 0 | 14 | 0 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides encryption and decryption utilities for saved objects containing sensitive information. | 51 | 0 | 44 | 0 | -| | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | Adds dashboards for discovering and managing Enterprise Search products. | 6 | 0 | 6 | 0 | +| | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | Adds dashboards for discovering and managing Enterprise Search products. | 5 | 0 | 5 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 115 | 3 | 111 | 3 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | The Event Annotation service contains expressions for event annotations | 200 | 0 | 200 | 6 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | The listing page for event annotations. | 15 | 0 | 15 | 0 | @@ -96,7 +96,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | The file upload plugin contains components and services for uploading a file, analyzing its data, and then importing the data into an Elasticsearch index. Supported file types include CSV, TSV, newline-delimited JSON and GeoJSON. | 59 | 0 | 59 | 2 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | File upload, download, sharing, and serving over HTTP implementation in Kibana. | 239 | 0 | 24 | 9 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Simple UI for managing files in Kibana | 2 | 0 | 2 | 0 | -| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1201 | 3 | 1083 | 41 | +| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1200 | 3 | 1082 | 41 | | ftrApis | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 68 | 0 | 14 | 5 | | globalSearchBar | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 0 | 0 | 0 | 0 | @@ -114,7 +114,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 123 | 2 | 96 | 4 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides UI and APIs for the interactive setup mode. | 28 | 0 | 18 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 6 | 0 | 6 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 186 | 0 | 147 | 5 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 176 | 0 | 138 | 4 | | kibanaUsageCollection | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | | [@elastic/kibana-app-services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 612 | 3 | 419 | 9 | | | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 5 | 0 | 5 | 1 | @@ -130,7 +130,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | - | 259 | 0 | 258 | 28 | | | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | - | 67 | 0 | 67 | 0 | | | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | Exposes utilities for accessing metrics data | 14 | 0 | 14 | 0 | -| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the machine learning features provided by Elastic. | 150 | 3 | 64 | 32 | +| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the machine learning features provided by Elastic. | 150 | 3 | 64 | 33 | | | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | - | 15 | 3 | 13 | 1 | | | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | - | 9 | 0 | 9 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 34 | 0 | 34 | 2 | @@ -141,12 +141,12 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 42 | 0 | 39 | 7 | | | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | This plugin exposes and registers observability log consumption features. | 12 | 0 | 12 | 1 | | | [@elastic/apm-ui](https://github.com/orgs/elastic/teams/apm-ui) | - | 14 | 0 | 14 | 0 | -| | [@elastic/observability-ui](https://github.com/orgs/elastic/teams/observability-ui) | - | 286 | 1 | 283 | 15 | +| | [@elastic/observability-ui](https://github.com/orgs/elastic/teams/observability-ui) | - | 287 | 1 | 284 | 15 | | | [@elastic/security-defend-workflows](https://github.com/orgs/elastic/teams/security-defend-workflows) | - | 24 | 0 | 24 | 7 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 2 | 0 | 2 | 0 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Presentation Utility Plugin is a set of common, shared components and toolkits for solutions within the Presentation space, (e.g. Dashboards, Canvas). | 218 | 2 | 164 | 11 | -| | [@elastic/profiling-ui](https://github.com/orgs/elastic/teams/profiling-ui) | - | 17 | 1 | 17 | 0 | -| | [@elastic/profiling-ui](https://github.com/orgs/elastic/teams/profiling-ui) | - | 21 | 0 | 21 | 5 | +| | [@elastic/profiling-ui](https://github.com/orgs/elastic/teams/profiling-ui) | - | 16 | 1 | 16 | 0 | +| | [@elastic/profiling-ui](https://github.com/orgs/elastic/teams/profiling-ui) | - | 21 | 0 | 21 | 6 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 4 | 0 | 4 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Reporting Services enables applications to feature reports that the user can automate with Watcher and download later. | 42 | 0 | 22 | 5 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 21 | 0 | 21 | 0 | @@ -428,7 +428,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 7 | 0 | 7 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 7 | 0 | 7 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 9 | 1 | 9 | 0 | -| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 101 | 0 | 85 | 0 | +| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 102 | 0 | 86 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 15 | 0 | 9 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 29 | 2 | 25 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 65 | 0 | 38 | 3 | @@ -507,11 +507,12 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 5 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 8 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 2 | 0 | 1 | 0 | -| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 8 | 0 | 8 | 0 | +| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 22 | 0 | 22 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 31 | 1 | 24 | 1 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 78 | 0 | 76 | 3 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 55 | 1 | 50 | 0 | | | [@elastic/actionable-observability](https://github.com/orgs/elastic/teams/actionable-observability) | - | 13 | 0 | 13 | 3 | +| | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 7 | 0 | 7 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 45 | 0 | 45 | 10 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 51 | 5 | 34 | 0 | | | [@elastic/security-asset-management](https://github.com/orgs/elastic/teams/security-asset-management) | - | 62 | 0 | 62 | 0 | @@ -616,7 +617,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 41 | 2 | 21 | 0 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 24 | 0 | 16 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 5 | 1 | -| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 289 | 4 | 242 | 12 | +| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 290 | 4 | 243 | 12 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 137 | 5 | 105 | 2 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 1 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 22 | 0 | 21 | 0 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index 927abbbb3ee13..d7b492ff54066 100644 --- a/api_docs/presentation_util.mdx +++ b/api_docs/presentation_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationUtil title: "presentationUtil" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationUtil plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/profiling.devdocs.json b/api_docs/profiling.devdocs.json index 10bfb3e0e27e6..f3e6f3535e41b 100644 --- a/api_docs/profiling.devdocs.json +++ b/api_docs/profiling.devdocs.json @@ -5,23 +5,7 @@ "functions": [], "interfaces": [], "enums": [], - "misc": [ - { - "parentPluginId": "profiling", - "id": "def-public.ProfilingLocators", - "type": "Type", - "tags": [], - "label": "ProfilingLocators", - "description": [], - "signature": [ - "any" - ], - "path": "x-pack/plugins/profiling/public/index.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - } - ], + "misc": [], "objects": [], "start": { "parentPluginId": "profiling", diff --git a/api_docs/profiling.mdx b/api_docs/profiling.mdx index 47827bb20466e..9ef2e27dd7756 100644 --- a/api_docs/profiling.mdx +++ b/api_docs/profiling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profiling title: "profiling" image: https://source.unsplash.com/400x175/?github description: API docs for the profiling plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; @@ -21,16 +21,13 @@ Contact [@elastic/profiling-ui](https://github.com/orgs/elastic/teams/profiling- | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 17 | 1 | 17 | 0 | +| 16 | 1 | 16 | 0 | ## Client ### Start -### Consts, variables and types - - ## Server ### Setup diff --git a/api_docs/profiling_data_access.devdocs.json b/api_docs/profiling_data_access.devdocs.json index 73b628d847d02..d8c8388226d4f 100644 --- a/api_docs/profiling_data_access.devdocs.json +++ b/api_docs/profiling_data_access.devdocs.json @@ -47,7 +47,9 @@ "section": "def-common.BaseFlameGraph", "text": "BaseFlameGraph" }, - ">; getStatus: ({ esClient, soClient, spaceId }: HasSetupParams) => Promise<", + ">; getStatus: ({ esClient, soClient, spaceId }: ", + "HasSetupParams", + ") => Promise<", { "pluginId": "@kbn/profiling-utils", "scope": "common", diff --git a/api_docs/profiling_data_access.mdx b/api_docs/profiling_data_access.mdx index ff0a1e375d4da..5a79e4f5054ea 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: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profilingDataAccess'] --- import profilingDataAccessObj from './profiling_data_access.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/profiling-ui](https://github.com/orgs/elastic/teams/profiling- | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 21 | 0 | 21 | 5 | +| 21 | 0 | 21 | 6 | ## Server diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index 5159030cfa617..b1e3eeec11aab 100644 --- a/api_docs/remote_clusters.mdx +++ b/api_docs/remote_clusters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/remoteClusters title: "remoteClusters" image: https://source.unsplash.com/400x175/?github description: API docs for the remoteClusters plugin -date: 2023-09-25 +date: 2023-09-26 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 488642c6f8e01..32c6085ed7987 100644 --- a/api_docs/reporting.mdx +++ b/api_docs/reporting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/reporting title: "reporting" image: https://source.unsplash.com/400x175/?github description: API docs for the reporting plugin -date: 2023-09-25 +date: 2023-09-26 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 4b61f0e98d41f..c951948e798df 100644 --- a/api_docs/rollup.mdx +++ b/api_docs/rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/rollup title: "rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the rollup plugin -date: 2023-09-25 +date: 2023-09-26 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 40ba43446183a..fb682878de661 100644 --- a/api_docs/rule_registry.mdx +++ b/api_docs/rule_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ruleRegistry title: "ruleRegistry" image: https://source.unsplash.com/400x175/?github description: API docs for the ruleRegistry plugin -date: 2023-09-25 +date: 2023-09-26 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 616ca2ba498b8..aed7a39727ab0 100644 --- a/api_docs/runtime_fields.mdx +++ b/api_docs/runtime_fields.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/runtimeFields title: "runtimeFields" image: https://source.unsplash.com/400x175/?github description: API docs for the runtimeFields plugin -date: 2023-09-25 +date: 2023-09-26 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 703a7351a6a16..98301ae5da2be 100644 --- a/api_docs/saved_objects.mdx +++ b/api_docs/saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjects title: "savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjects plugin -date: 2023-09-25 +date: 2023-09-26 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 73360ea45e933..52cc877c8727d 100644 --- a/api_docs/saved_objects_finder.mdx +++ b/api_docs/saved_objects_finder.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsFinder title: "savedObjectsFinder" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsFinder plugin -date: 2023-09-25 +date: 2023-09-26 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 99bfb91df0e6f..9c191aa176a6a 100644 --- a/api_docs/saved_objects_management.mdx +++ b/api_docs/saved_objects_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsManagement title: "savedObjectsManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsManagement plugin -date: 2023-09-25 +date: 2023-09-26 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 de4d4be113027..7313cdcd0d8b7 100644 --- a/api_docs/saved_objects_tagging.mdx +++ b/api_docs/saved_objects_tagging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTagging title: "savedObjectsTagging" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTagging plugin -date: 2023-09-25 +date: 2023-09-26 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 0e6c7c151cb33..115ba3370474b 100644 --- a/api_docs/saved_objects_tagging_oss.mdx +++ b/api_docs/saved_objects_tagging_oss.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTaggingOss title: "savedObjectsTaggingOss" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTaggingOss plugin -date: 2023-09-25 +date: 2023-09-26 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 6dc1bacc404b9..45828377b6b31 100644 --- a/api_docs/saved_search.mdx +++ b/api_docs/saved_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedSearch title: "savedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the savedSearch plugin -date: 2023-09-25 +date: 2023-09-26 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 18be4227f6605..ff6bd17c5503d 100644 --- a/api_docs/screenshot_mode.mdx +++ b/api_docs/screenshot_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotMode title: "screenshotMode" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotMode plugin -date: 2023-09-25 +date: 2023-09-26 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 38761b32e479c..da03e80963f9e 100644 --- a/api_docs/screenshotting.mdx +++ b/api_docs/screenshotting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotting title: "screenshotting" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotting plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/security.mdx b/api_docs/security.mdx index 98d5fffabba4a..32d50ac6e42d8 100644 --- a/api_docs/security.mdx +++ b/api_docs/security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/security title: "security" image: https://source.unsplash.com/400x175/?github description: API docs for the security plugin -date: 2023-09-25 +date: 2023-09-26 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 c68539310812e..8b26f3c4e928d 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolution title: "securitySolution" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolution plugin -date: 2023-09-25 +date: 2023-09-26 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 cc41316aed3ff..713e3bc175b32 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: 2023-09-25 +date: 2023-09-26 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 8ef81c1dfca95..e520082f856b0 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: 2023-09-25 +date: 2023-09-26 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 41a6ccc0869ef..078d0d12d34a5 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: 2023-09-25 +date: 2023-09-26 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 50d9d52e50c73..e13f8bdee1cee 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: 2023-09-25 +date: 2023-09-26 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 01d50142e9ce9..0137fbc3b99ed 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: 2023-09-25 +date: 2023-09-26 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 cb13977aa0474..990d781dcd778 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/sessionView title: "sessionView" image: https://source.unsplash.com/400x175/?github description: API docs for the sessionView plugin -date: 2023-09-25 +date: 2023-09-26 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 84f7168288c65..3d246a4cf0c76 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/share title: "share" image: https://source.unsplash.com/400x175/?github description: API docs for the share plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index f6981f2ac3afc..d78a24c2ab160 100644 --- a/api_docs/snapshot_restore.mdx +++ b/api_docs/snapshot_restore.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/snapshotRestore title: "snapshotRestore" image: https://source.unsplash.com/400x175/?github description: API docs for the snapshotRestore plugin -date: 2023-09-25 +date: 2023-09-26 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 c60ccfacf2789..9cfa673edc64c 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/spaces title: "spaces" image: https://source.unsplash.com/400x175/?github description: API docs for the spaces plugin -date: 2023-09-25 +date: 2023-09-26 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 8a51514e1c06e..906e62d9f0ac2 100644 --- a/api_docs/stack_alerts.mdx +++ b/api_docs/stack_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackAlerts title: "stackAlerts" image: https://source.unsplash.com/400x175/?github description: API docs for the stackAlerts plugin -date: 2023-09-25 +date: 2023-09-26 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 40b967ce8965a..4f2b54a1925a6 100644 --- a/api_docs/stack_connectors.mdx +++ b/api_docs/stack_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackConnectors title: "stackConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the stackConnectors plugin -date: 2023-09-25 +date: 2023-09-26 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 b96ec3d7afc73..5db4c79809e60 100644 --- a/api_docs/task_manager.mdx +++ b/api_docs/task_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/taskManager title: "taskManager" image: https://source.unsplash.com/400x175/?github description: API docs for the taskManager plugin -date: 2023-09-25 +date: 2023-09-26 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 978da104cf14b..d78fcb461a8f5 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetry title: "telemetry" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetry plugin -date: 2023-09-25 +date: 2023-09-26 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 b05b5cbc2f13b..e34eddbdef694 100644 --- a/api_docs/telemetry_collection_manager.mdx +++ b/api_docs/telemetry_collection_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionManager title: "telemetryCollectionManager" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionManager plugin -date: 2023-09-25 +date: 2023-09-26 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 96f0f4ceb59d6..0be6e03857399 100644 --- a/api_docs/telemetry_collection_xpack.mdx +++ b/api_docs/telemetry_collection_xpack.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionXpack title: "telemetryCollectionXpack" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionXpack plugin -date: 2023-09-25 +date: 2023-09-26 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 a0a03154ba4a3..fe66b6a93fea0 100644 --- a/api_docs/telemetry_management_section.mdx +++ b/api_docs/telemetry_management_section.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryManagementSection title: "telemetryManagementSection" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryManagementSection plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/text_based_languages.mdx b/api_docs/text_based_languages.mdx index 102620c30738e..4225392065de1 100644 --- a/api_docs/text_based_languages.mdx +++ b/api_docs/text_based_languages.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/textBasedLanguages title: "textBasedLanguages" image: https://source.unsplash.com/400x175/?github description: API docs for the textBasedLanguages plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'textBasedLanguages'] --- import textBasedLanguagesObj from './text_based_languages.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index 3101b46e527b7..14b879c5117a3 100644 --- a/api_docs/threat_intelligence.mdx +++ b/api_docs/threat_intelligence.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/threatIntelligence title: "threatIntelligence" image: https://source.unsplash.com/400x175/?github description: API docs for the threatIntelligence plugin -date: 2023-09-25 +date: 2023-09-26 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 6df86f6405a46..fbf37cdfd2c28 100644 --- a/api_docs/timelines.mdx +++ b/api_docs/timelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/timelines title: "timelines" image: https://source.unsplash.com/400x175/?github description: API docs for the timelines plugin -date: 2023-09-25 +date: 2023-09-26 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 b2abf3b5a7fbd..474c42fe42811 100644 --- a/api_docs/transform.mdx +++ b/api_docs/transform.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/transform title: "transform" image: https://source.unsplash.com/400x175/?github description: API docs for the transform plugin -date: 2023-09-25 +date: 2023-09-26 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 c71f65522d050..509e4f6ac6055 100644 --- a/api_docs/triggers_actions_ui.mdx +++ b/api_docs/triggers_actions_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/triggersActionsUi title: "triggersActionsUi" image: https://source.unsplash.com/400x175/?github description: API docs for the triggersActionsUi plugin -date: 2023-09-25 +date: 2023-09-26 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 6732a7c289ec6..ab4dc0626aceb 100644 --- a/api_docs/ui_actions.mdx +++ b/api_docs/ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActions title: "uiActions" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActions plugin -date: 2023-09-25 +date: 2023-09-26 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 59462b448fcdc..d2ac48d5b2cf7 100644 --- a/api_docs/ui_actions_enhanced.mdx +++ b/api_docs/ui_actions_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActionsEnhanced title: "uiActionsEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActionsEnhanced plugin -date: 2023-09-25 +date: 2023-09-26 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 250bdf0cd888d..73ef1bfd0fad5 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: 2023-09-25 +date: 2023-09-26 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 1146ce60ba21b..b92bf316eee55 100644 --- a/api_docs/unified_histogram.mdx +++ b/api_docs/unified_histogram.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedHistogram title: "unifiedHistogram" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedHistogram plugin -date: 2023-09-25 +date: 2023-09-26 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 b64502052bb92..9f6b9c0cba07f 100644 --- a/api_docs/unified_search.mdx +++ b/api_docs/unified_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch title: "unifiedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch plugin -date: 2023-09-25 +date: 2023-09-26 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 83ef9b6a1b3ba..f65133a07c62c 100644 --- a/api_docs/unified_search_autocomplete.mdx +++ b/api_docs/unified_search_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch-autocomplete title: "unifiedSearch.autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch.autocomplete plugin -date: 2023-09-25 +date: 2023-09-26 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 482d11bcd7144..35caa52836dbe 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: 2023-09-25 +date: 2023-09-26 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 2777090c13a13..a6308c5cd7fa8 100644 --- a/api_docs/url_forwarding.mdx +++ b/api_docs/url_forwarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/urlForwarding title: "urlForwarding" image: https://source.unsplash.com/400x175/?github description: API docs for the urlForwarding plugin -date: 2023-09-25 +date: 2023-09-26 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 57957d3e2c797..46bd23e945816 100644 --- a/api_docs/usage_collection.mdx +++ b/api_docs/usage_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/usageCollection title: "usageCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the usageCollection plugin -date: 2023-09-25 +date: 2023-09-26 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 4044e6cbe18d5..1691005a61bfe 100644 --- a/api_docs/ux.mdx +++ b/api_docs/ux.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ux title: "ux" image: https://source.unsplash.com/400x175/?github description: API docs for the ux plugin -date: 2023-09-25 +date: 2023-09-26 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 228fb2a2daefc..e884419d9c22e 100644 --- a/api_docs/vis_default_editor.mdx +++ b/api_docs/vis_default_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visDefaultEditor title: "visDefaultEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the visDefaultEditor plugin -date: 2023-09-25 +date: 2023-09-26 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 52cec1def36a2..5b692b69164cc 100644 --- a/api_docs/vis_type_gauge.mdx +++ b/api_docs/vis_type_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeGauge title: "visTypeGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeGauge plugin -date: 2023-09-25 +date: 2023-09-26 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 41d0ec04429c0..08e1dbc25d94d 100644 --- a/api_docs/vis_type_heatmap.mdx +++ b/api_docs/vis_type_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeHeatmap title: "visTypeHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeHeatmap plugin -date: 2023-09-25 +date: 2023-09-26 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 b80f235179cc5..b246d688749dd 100644 --- a/api_docs/vis_type_pie.mdx +++ b/api_docs/vis_type_pie.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypePie title: "visTypePie" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypePie plugin -date: 2023-09-25 +date: 2023-09-26 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 dded79de20576..7870c03d8aacc 100644 --- a/api_docs/vis_type_table.mdx +++ b/api_docs/vis_type_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTable title: "visTypeTable" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTable plugin -date: 2023-09-25 +date: 2023-09-26 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 9a8a28291e8eb..80dc7190498e2 100644 --- a/api_docs/vis_type_timelion.mdx +++ b/api_docs/vis_type_timelion.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimelion title: "visTypeTimelion" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimelion plugin -date: 2023-09-25 +date: 2023-09-26 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 fcf9330494758..a697c1614530e 100644 --- a/api_docs/vis_type_timeseries.mdx +++ b/api_docs/vis_type_timeseries.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimeseries title: "visTypeTimeseries" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimeseries plugin -date: 2023-09-25 +date: 2023-09-26 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 e676666e890e9..68588ef9609e4 100644 --- a/api_docs/vis_type_vega.mdx +++ b/api_docs/vis_type_vega.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVega title: "visTypeVega" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVega plugin -date: 2023-09-25 +date: 2023-09-26 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 fa7a9edf9e366..b23f402737a4d 100644 --- a/api_docs/vis_type_vislib.mdx +++ b/api_docs/vis_type_vislib.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVislib title: "visTypeVislib" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVislib plugin -date: 2023-09-25 +date: 2023-09-26 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 2065f8dfddf38..956c3d1bcf162 100644 --- a/api_docs/vis_type_xy.mdx +++ b/api_docs/vis_type_xy.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeXy title: "visTypeXy" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeXy plugin -date: 2023-09-25 +date: 2023-09-26 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 b24038325797e..2d749827cb5c2 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visualizations title: "visualizations" image: https://source.unsplash.com/400x175/?github description: API docs for the visualizations plugin -date: 2023-09-25 +date: 2023-09-26 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; From 0cf5ba15fe9d24d30f88a096915e329d2f6143cb Mon Sep 17 00:00:00 2001 From: Khristinin Nikita Date: Tue, 26 Sep 2023 08:01:59 +0200 Subject: [PATCH 42/45] Fix exceptions flyout disappearing (#166914) ## Summary fix: [https://github.com/elastic/kibana/issues/166616](https://github.com/elastic/kibana/issues/166616) When we open exception flyout we do request a rule Then in the rule details page, `alertDefaultFilters` was memoized based on whole rule object And if the rule changes it rerenders the whole alerts table. In the attached video it rule changes because of rule execution time. I make `useMemo` and `use effect` for these cases really on rule property, but not full object https://github.com/elastic/kibana/assets/7609147/eba7c3ce-84b9-47a7-8bc9-a15bc0179e2c --- .../rule_details_ui/pages/rule_details/index.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx index 674d29b128413..97f02b8e35cf2 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx @@ -233,6 +233,7 @@ const RuleDetailsPageComponent: React.FC = ({ detailName: string; tabName: string; }>(); + const { rule: maybeRule, refresh: refreshRule, @@ -382,19 +383,21 @@ const RuleDetailsPageComponent: React.FC = ({ [clearEventsLoading, clearEventsDeleted, clearSelected, setFilterGroup] ); + const isBuildingBlockTypeNotNull = rule?.building_block_type != null; // Set showBuildingBlockAlerts if rule is a Building Block Rule otherwise we won't show alerts useEffect(() => { - setShowBuildingBlockAlerts(rule?.building_block_type != null); - }, [rule, setShowBuildingBlockAlerts]); + setShowBuildingBlockAlerts(isBuildingBlockTypeNotNull); + }, [isBuildingBlockTypeNotNull, setShowBuildingBlockAlerts]); + const ruleRuleId = rule?.rule_id ?? ''; const alertDefaultFilters = useMemo( () => [ - ...buildAlertsFilter(rule?.rule_id ?? ''), + ...buildAlertsFilter(ruleRuleId ?? ''), ...buildShowBuildingBlockFilter(showBuildingBlockAlerts), ...buildAlertStatusFilter(filterGroup), ...buildThreatMatchFilter(showOnlyThreatIndicatorAlerts), ], - [rule, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts, filterGroup] + [ruleRuleId, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts, filterGroup] ); const alertMergedFilters = useMemo( From 5ede05f558cd552a443844b785b82ad4598bb8a9 Mon Sep 17 00:00:00 2001 From: Achyut Jhunjhunwala Date: Tue, 26 Sep 2023 09:25:32 +0200 Subject: [PATCH 43/45] [APM] ADD logic to capture telemetry for metricset with and without rollups (#166598) ## Summary Resolves 1. https://github.com/elastic/kibana/issues/161981 2. https://github.com/elastic/kibana/issues/161984 3. It also adds the same statistics for last day ## How to test A deployment has been prepared using the Chrome Extension. (It uses Obs Environment, so data is present) Please go to this end point to see a similar payload in screenshot > https://achyutjhunjhunwala-d-pr166598.kb.us-west2.gcp.elastic-cloud.com/internal/apm/debug-telemetry image --- .../__snapshots__/apm_telemetry.test.ts.snap | 772 ++++++++++++++++++ .../__snapshots__/tasks.test.ts.snap | 617 ++++++++++++++ .../collect_data_telemetry/tasks.test.ts | 244 ++++-- .../collect_data_telemetry/tasks.ts | 177 +++- .../apm/server/lib/apm_telemetry/schema.ts | 71 +- .../lib/apm_telemetry/telemetry_client.ts | 25 +- .../apm/server/lib/apm_telemetry/types.ts | 41 + .../schema/xpack_plugins.json | 772 ++++++++++++++++++ 8 files changed, 2660 insertions(+), 59 deletions(-) create mode 100644 x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/__snapshots__/tasks.test.ts.snap diff --git a/x-pack/plugins/apm/common/__snapshots__/apm_telemetry.test.ts.snap b/x-pack/plugins/apm/common/__snapshots__/apm_telemetry.test.ts.snap index d84aa51a0e365..0f4e6becae335 100644 --- a/x-pack/plugins/apm/common/__snapshots__/apm_telemetry.test.ts.snap +++ b/x-pack/plugins/apm/common/__snapshots__/apm_telemetry.test.ts.snap @@ -1694,6 +1694,778 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the } } } + }, + "metricset": { + "properties": { + "service_destination-1m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "service_destination-10m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "service_destination-60m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "transaction-1m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "transaction-10m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "transaction-60m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "service_summary-1m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "service_summary-10m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "service_summary-60m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "service_transaction-1m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "service_transaction-10m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "service_transaction-60m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "span_breakdown-1m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "span_breakdown-10m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "span_breakdown-60m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "app": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + } + } } } }, diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/__snapshots__/tasks.test.ts.snap b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/__snapshots__/tasks.test.ts.snap new file mode 100644 index 0000000000000..0cfc50412dac4 --- /dev/null +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/__snapshots__/tasks.test.ts.snap @@ -0,0 +1,617 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`data telemetry collection tasks indices_stats returns a map of index stats 1`] = ` +Object { + "indices": Object { + "all": Object { + "total": Object { + "docs": Object { + "count": 2, + }, + "store": Object { + "size_in_bytes": 100, + }, + }, + }, + "metric": Object { + "all": Object { + "total": Object { + "docs": Object { + "count": 2, + }, + "store": Object { + "size_in_bytes": 100, + }, + }, + }, + "metricset": Object { + "app": Object { + "1d": Object { + "doc_count": 6, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 1, + }, + "shards": 2, + "store": Object { + "size_in_bytes": 50, + }, + }, + }, + }, + "service_destination-10m": Object { + "1d": Object { + "doc_count": 3, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 1, + }, + "shards": 2, + "store": Object { + "size_in_bytes": 50, + }, + }, + }, + }, + "service_destination-1m": Object { + "1d": Object { + "doc_count": 3, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 1, + }, + "shards": 2, + "store": Object { + "size_in_bytes": 50, + }, + }, + }, + }, + "service_destination-60m": Object { + "1d": Object { + "doc_count": 3, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 1, + }, + "shards": 2, + "store": Object { + "size_in_bytes": 50, + }, + }, + }, + }, + "service_summary-10m": Object { + "1d": Object { + "doc_count": 9, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 1, + }, + "shards": 2, + "store": Object { + "size_in_bytes": 50, + }, + }, + }, + }, + "service_summary-1m": Object { + "1d": Object { + "doc_count": 12, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 1, + }, + "shards": 2, + "store": Object { + "size_in_bytes": 50, + }, + }, + }, + }, + "service_summary-60m": Object { + "1d": Object { + "doc_count": 9, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 1, + }, + "shards": 2, + "store": Object { + "size_in_bytes": 50, + }, + }, + }, + }, + "service_transaction-10m": Object { + "1d": Object { + "doc_count": 6, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 1, + }, + "shards": 2, + "store": Object { + "size_in_bytes": 50, + }, + }, + }, + }, + "service_transaction-1m": Object { + "1d": Object { + "doc_count": 6, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 1, + }, + "shards": 2, + "store": Object { + "size_in_bytes": 50, + }, + }, + }, + }, + "service_transaction-60m": Object { + "1d": Object { + "doc_count": 6, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 1, + }, + "shards": 2, + "store": Object { + "size_in_bytes": 50, + }, + }, + }, + }, + "span_breakdown-10m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 1, + }, + "shards": 2, + "store": Object { + "size_in_bytes": 50, + }, + }, + }, + }, + "span_breakdown-1m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 1, + }, + "shards": 2, + "store": Object { + "size_in_bytes": 50, + }, + }, + }, + }, + "span_breakdown-60m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 1, + }, + "shards": 2, + "store": Object { + "size_in_bytes": 50, + }, + }, + }, + }, + "transaction-10m": Object { + "1d": Object { + "doc_count": 6, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 1, + }, + "shards": 2, + "store": Object { + "size_in_bytes": 50, + }, + }, + }, + }, + "transaction-1m": Object { + "1d": Object { + "doc_count": 6, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 1, + }, + "shards": 2, + "store": Object { + "size_in_bytes": 50, + }, + }, + }, + }, + "transaction-60m": Object { + "1d": Object { + "doc_count": 6, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 1, + }, + "shards": 2, + "store": Object { + "size_in_bytes": 50, + }, + }, + }, + }, + }, + "shards": Object { + "total": 2, + }, + }, + "shards": Object { + "total": 2, + }, + "traces": Object { + "all": Object { + "total": Object { + "docs": Object { + "count": 2, + }, + "store": Object { + "size_in_bytes": 100, + }, + }, + }, + "shards": Object { + "total": 2, + }, + }, + }, +} +`; + +exports[`data telemetry collection tasks indices_stats with no results 1`] = ` +Object { + "indices": Object { + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + "metric": Object { + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + "metricset": Object { + "app": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "shards": 0, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + }, + "service_destination-10m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "shards": 0, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + }, + "service_destination-1m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "shards": 0, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + }, + "service_destination-60m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "shards": 0, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + }, + "service_summary-10m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "shards": 0, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + }, + "service_summary-1m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "shards": 0, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + }, + "service_summary-60m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "shards": 0, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + }, + "service_transaction-10m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "shards": 0, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + }, + "service_transaction-1m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "shards": 0, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + }, + "service_transaction-60m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "shards": 0, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + }, + "span_breakdown-10m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "shards": 0, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + }, + "span_breakdown-1m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "shards": 0, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + }, + "span_breakdown-60m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "shards": 0, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + }, + "transaction-10m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "shards": 0, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + }, + "transaction-1m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "shards": 0, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + }, + "transaction-60m": Object { + "1d": Object { + "doc_count": 0, + }, + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "shards": 0, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + }, + }, + "shards": Object { + "total": 0, + }, + }, + "shards": Object { + "total": 0, + }, + "traces": Object { + "all": Object { + "total": Object { + "docs": Object { + "count": 0, + }, + "store": Object { + "size_in_bytes": 0, + }, + }, + }, + "shards": Object { + "total": 0, + }, + }, + }, +} +`; diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.test.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.test.ts index ba9d06b78bfae..5293a026e5b48 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.test.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.test.ts @@ -12,6 +12,7 @@ import { SERVICE_NAME, SERVICE_ENVIRONMENT, } from '../../../../common/es_fields/apm'; +import { IndicesStatsResponse } from '../telemetry_client'; describe('data telemetry collection tasks', () => { const indices = { @@ -376,74 +377,223 @@ describe('data telemetry collection tasks', () => { const task = tasks.find((t) => t.name === 'indices_stats'); it('returns a map of index stats', async () => { - const indicesStats = jest.fn().mockResolvedValue({ - _all: { total: { docs: { count: 1 }, store: { size_in_bytes: 1 } } }, - _shards: { total: 1 }, - }); - - const statsResponse = { - shards: { - total: 1, + const indicesStatsResponse: IndicesStatsResponse = { + _shards: { + total: 2, }, - all: { + _all: { total: { + store: { + size_in_bytes: 100, + }, + docs: { + count: 2, + }, + }, + primaries: { docs: { count: 1, }, store: { - size_in_bytes: 1, + size_in_bytes: 50, + total_data_set_size_in_bytes: 50, }, }, }, }; + const searchResponse = { + aggregations: { + metricsets: { + buckets: [ + { + key: 'service_transaction', + doc_count: 3240, + rollup_interval: { + buckets: [ + { + key: '10m', + doc_count: 1080, + metrics_value_count: { + value: 6, + }, + }, + { + key: '1m', + doc_count: 1080, + metrics_value_count: { + value: 6, + }, + }, + { + key: '60m', + doc_count: 1080, + metrics_value_count: { + value: 6, + }, + }, + ], + }, + }, + { + key: 'transaction', + doc_count: 3240, + rollup_interval: { + buckets: [ + { + key: '10m', + doc_count: 1080, + metrics_value_count: { + value: 6, + }, + }, + { + key: '1m', + doc_count: 1080, + metrics_value_count: { + value: 6, + }, + }, + { + key: '60m', + doc_count: 1080, + metrics_value_count: { + value: 6, + }, + }, + ], + }, + }, + { + key: 'service_destination', + doc_count: 1620, + rollup_interval: { + buckets: [ + { + key: '10m', + doc_count: 540, + metrics_value_count: { + value: 3, + }, + }, + { + key: '1m', + doc_count: 540, + metrics_value_count: { + value: 3, + }, + }, + { + key: '60m', + doc_count: 540, + metrics_value_count: { + value: 3, + }, + }, + ], + }, + }, + { + key: 'service_summary', + doc_count: 30, + rollup_interval: { + buckets: [ + { + key: '1m', + doc_count: 12, + metrics_value_count: { + value: 12, + }, + }, + { + key: '10m', + doc_count: 9, + metrics_value_count: { + value: 9, + }, + }, + { + key: '60m', + doc_count: 9, + metrics_value_count: { + value: 9, + }, + }, + ], + }, + }, + { + key: 'span_breakdown', + doc_count: 12, + rollup_interval: { + buckets: [], + }, + }, + { + key: 'app', + doc_count: 6, + rollup_interval: { + buckets: [], + }, + }, + ], + }, + }, + }; + + const indicesStats = jest.fn().mockResolvedValue(indicesStatsResponse); + const search = jest.fn().mockResolvedValue(searchResponse); + expect( await task?.executor({ indices, - telemetryClient: { indicesStats }, + telemetryClient: { + indicesStats, + search, + }, } as any) - ).toEqual({ - indices: { - ...statsResponse, - metric: statsResponse, - traces: statsResponse, - }, - }); + ).toMatchSnapshot(); }); - - describe('with no results', () => { - it('returns zero values', async () => { - const indicesStats = jest.fn().mockResolvedValue({}); - - const statsResponse = { - shards: { - total: 0, + it('with no results', async () => { + const indicesStatsResponse: IndicesStatsResponse = { + _shards: { + total: 0, + }, + _all: { + total: { + store: { + size_in_bytes: 0, + }, + docs: { + count: 0, + }, }, - all: { - total: { - docs: { - count: 0, - }, - store: { - size_in_bytes: 0, - }, + primaries: { + docs: { + count: 0, + }, + store: { + size_in_bytes: 0, + total_data_set_size_in_bytes: 0, }, }, - }; + }, + }; - expect( - await task?.executor({ - indices, - telemetryClient: { indicesStats }, - } as any) - ).toEqual({ - indices: { - ...statsResponse, - metric: statsResponse, - traces: statsResponse, + const searchResponse = {}; + + const indicesStats = jest.fn().mockResolvedValue(indicesStatsResponse); + const search = jest.fn().mockResolvedValue(searchResponse); + + expect( + await task?.executor({ + indices, + telemetryClient: { + indicesStats, + search, }, - }); - }); + } as any) + ).toMatchSnapshot(); }); }); diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts index aad51e5ed1c5d..d5e9203446c38 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts @@ -26,6 +26,8 @@ import { HOST_NAME, HOST_OS_PLATFORM, KUBERNETES_POD_NAME, + METRICSET_INTERVAL, + METRICSET_NAME, OBSERVER_HOSTNAME, PARENT_ID, PROCESSOR_EVENT, @@ -39,12 +41,12 @@ import { SERVICE_RUNTIME_NAME, SERVICE_RUNTIME_VERSION, SERVICE_VERSION, + SPAN_DESTINATION_SERVICE_RESOURCE, TRACE_ID, TRANSACTION_NAME, TRANSACTION_RESULT, TRANSACTION_TYPE, USER_AGENT_ORIGINAL, - SPAN_DESTINATION_SERVICE_RESOURCE, } from '../../../../common/es_fields/apm'; import { APM_SERVICE_GROUP_SAVED_OBJECT_TYPE, @@ -57,9 +59,18 @@ import { APMError } from '../../../../typings/es_schemas/ui/apm_error'; import { AgentName } from '../../../../typings/es_schemas/ui/fields/agent'; import { Span } from '../../../../typings/es_schemas/ui/span'; import { Transaction } from '../../../../typings/es_schemas/ui/transaction'; -import { APMTelemetry, APMPerService, APMDataTelemetry } from '../types'; +import { + APMDataTelemetry, + APMPerService, + APMTelemetry, + DataStreamStats, + MetricNotSupportingRollup, + MetricRollupIntervals, + MetricSupportingRollUp, +} from '../types'; import { APM_AGENT_CONFIGURATION_INDEX } from '../../../routes/settings/apm_indices/apm_system_index_constants'; -import { TelemetryClient } from '../telemetry_client'; +import { IndicesStatsResponse, TelemetryClient } from '../telemetry_client'; +import { RollupInterval } from '../../../../common/rollup'; type ISavedObjectsClient = Pick; const TIME_RANGES = ['1d', 'all'] as const; @@ -1082,6 +1093,163 @@ export const tasks: TelemetryTask[] = [ { name: 'indices_stats', executor: async ({ indices, telemetryClient }) => { + const dataStreamStatsDictionary = {} as DataStreamStats; + + const metricSetsSupportingRollUps: MetricSupportingRollUp[] = [ + 'service_destination', + 'service_transaction', + 'service_summary', + 'transaction', + 'span_breakdown', + ]; + + const metricSetsNotSupportingRollUps: MetricNotSupportingRollup[] = [ + 'app', + ]; + + const rollUpIntervals: MetricRollupIntervals[] = [ + RollupInterval.OneMinute, + RollupInterval.TenMinutes, + RollupInterval.SixtyMinutes, + ]; + + const populateDataStreamStatsDict = ( + ds: DataStreamStats, + key: string, + response: IndicesStatsResponse + ) => { + ds[key] = ds[key] || {}; + ds[key].all = { + total: { + shards: response?._shards?.total ?? 0, + docs: { + count: response?._all?.primaries?.docs?.count ?? 0, + }, + store: { + size_in_bytes: + response?._all?.primaries?.store?.size_in_bytes ?? 0, + }, + }, + }; + + return ds; + }; + + // The API calls must be done in series rather than in parallel due to the nature + // of how tasks are executed. We don't want to burden the customers instances + // which could directly impact the performance on the UI. + const fetchRollupMetrics = async () => { + for (const metricSet of metricSetsSupportingRollUps) { + for (const bucketSize of rollUpIntervals) { + const datastream = `metrics-apm.${metricSet}.${bucketSize}-*`; + const response = await telemetryClient.indicesStats({ + index: [datastream], + expand_wildcards: 'all', + filter_path: [ + '_all.primaries.docs', + '_all.primaries.store', + '_shards', + ], + }); + populateDataStreamStatsDict( + dataStreamStatsDictionary, + `${metricSet}-${bucketSize}`, + response + ); + } + } + }; + + const fetchMetricWithoutRollup = async () => { + for (const metricSet of metricSetsNotSupportingRollUps) { + const datastream = `metrics-apm.${metricSet}*`; + const response = await telemetryClient.indicesStats({ + index: [datastream], + expand_wildcards: 'all', + filter_path: [ + '_all.primaries.docs', + '_all.primaries.store', + '_shards', + ], + }); + populateDataStreamStatsDict( + dataStreamStatsDictionary, + metricSet, + response + ); + } + }; + + await fetchRollupMetrics(); + await fetchMetricWithoutRollup(); + + const lastDayStatsResponse = await telemetryClient.search({ + index: [indices.metric], + expand_wildcards: 'all', + body: { + track_total_hits: false, + size: 0, + timeout, + query: range1d, + aggs: { + metricsets: { + terms: { + field: METRICSET_NAME, + }, + aggs: { + rollup_interval: { + terms: { + field: METRICSET_INTERVAL, + }, + aggs: { + metrics_value_count: { + value_count: { + field: METRICSET_INTERVAL, + }, + }, + }, + }, + }, + }, + }, + }, + }); + + for (const metricSet of metricSetsSupportingRollUps) { + const metricSetData = + lastDayStatsResponse.aggregations?.metricsets?.buckets?.find( + (bucket) => bucket.key === metricSet + ); + + rollUpIntervals.forEach((interval) => { + const key = `${metricSet}-${interval}`; + dataStreamStatsDictionary[key]['1d'] = { + doc_count: 0, + }; + }); + + if (metricSetData?.rollup_interval?.buckets) { + for (const intervalBucket of metricSetData.rollup_interval.buckets) { + const intervalKey = intervalBucket.key as MetricRollupIntervals; + const intervalDocCount = intervalBucket.metrics_value_count.value; + dataStreamStatsDictionary[`${metricSet}-${intervalKey}`]['1d'] = { + doc_count: intervalDocCount, + }; + } + } + } + + for (const metricSet of metricSetsNotSupportingRollUps) { + const metricSetData = + lastDayStatsResponse.aggregations?.metricsets?.buckets?.find( + (bucket) => bucket.key === metricSet + ); + + dataStreamStatsDictionary[metricSet]['1d'] = { + doc_count: metricSetData?.doc_count || 0, + }; + } + const response = await telemetryClient.indicesStats({ index: [ APM_AGENT_CONFIGURATION_INDEX, @@ -1119,6 +1287,9 @@ export const tasks: TelemetryTask[] = [ }, }, }, + metricset: { + ...dataStreamStatsDictionary, + }, }, traces: { shards: { diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/schema.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/schema.ts index 1c41229b47bca..ccc6dd4ab01b7 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/schema.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/schema.ts @@ -6,7 +6,12 @@ */ import { MakeSchemaFrom } from '@kbn/usage-collection-plugin/server'; -import { AggregatedTransactionsCounts, APMUsage, APMPerService } from './types'; +import { + AggregatedTransactionsCounts, + APMUsage, + APMPerService, + DataStreamCombined, +} from './types'; import { ElasticAgentName } from '../../../typings/es_schemas/ui/fields/agent'; const aggregatedTransactionCountSchema: MakeSchemaFrom< @@ -27,6 +32,47 @@ const aggregatedTransactionCountSchema: MakeSchemaFrom< }, }; +const dataStreamCombinedSchema: MakeSchemaFrom = { + all: { + total: { + shards: { + type: 'long', + _meta: { + description: + 'Total number of shards for the given metricset per rollup interval.', + }, + }, + docs: { + count: { + type: 'long', + _meta: { + description: + 'Total number of metric documents in the primary shard for the given metricset per rollup interval', + }, + }, + }, + store: { + size_in_bytes: { + type: 'long', + _meta: { + description: + 'Size of the metric index in the primary shard for the given metricset per rollup interval', + }, + }, + }, + }, + }, + '1d': { + doc_count: { + type: 'long', + _meta: { + description: + 'Document count for the last day for a given metricset and rollup interval', + }, + }, + }, +}; + const agentSchema: MakeSchemaFrom['agents'][ElasticAgentName] = { agent: { @@ -924,6 +970,29 @@ export const apmSchema: MakeSchemaFrom = { }, }, }, + metricset: { + 'service_destination-1m': dataStreamCombinedSchema, + 'service_destination-10m': dataStreamCombinedSchema, + 'service_destination-60m': dataStreamCombinedSchema, + + 'transaction-1m': dataStreamCombinedSchema, + 'transaction-10m': dataStreamCombinedSchema, + 'transaction-60m': dataStreamCombinedSchema, + + 'service_summary-1m': dataStreamCombinedSchema, + 'service_summary-10m': dataStreamCombinedSchema, + 'service_summary-60m': dataStreamCombinedSchema, + + 'service_transaction-1m': dataStreamCombinedSchema, + 'service_transaction-10m': dataStreamCombinedSchema, + 'service_transaction-60m': dataStreamCombinedSchema, + + 'span_breakdown-1m': dataStreamCombinedSchema, + 'span_breakdown-10m': dataStreamCombinedSchema, + 'span_breakdown-60m': dataStreamCombinedSchema, + + app: dataStreamCombinedSchema, + }, }, traces: { shards: { diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/telemetry_client.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/telemetry_client.ts index b596166d91f2c..8afcd019233de 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/telemetry_client.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/telemetry_client.ts @@ -15,6 +15,22 @@ interface RequiredSearchParams { body: { size: number; track_total_hits: boolean | number; timeout: string }; } +export interface IndicesStatsResponse { + _all?: { + total?: { store?: { size_in_bytes?: number }; docs?: { count?: number } }; + primaries?: { + docs?: { count?: number }; + store?: { + size_in_bytes?: number; + total_data_set_size_in_bytes?: number; + }; + }; + }; + _shards?: { + total?: number; + }; +} + export interface TelemetryClient { search( params: TSearchRequest @@ -24,14 +40,7 @@ export interface TelemetryClient { params: estypes.IndicesStatsRequest // promise returned by client has an abort property // so we cannot use its ReturnType - ): Promise<{ - _all?: { - total?: { store?: { size_in_bytes?: number }; docs?: { count?: number } }; - }; - _shards?: { - total?: number; - }; - }>; + ): Promise; transportRequest: (params: { path: string; diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts index d5c16a6b3692a..eebce519e73d5 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts @@ -10,6 +10,7 @@ import { AgentName, ElasticAgentName, } from '../../../typings/es_schemas/ui/fields/agent'; +import { RollupInterval } from '../../../common/rollup'; export interface TimeframeMap { '1d': number; @@ -191,6 +192,7 @@ export interface APMUsage { }; }; }; + metricset: DataStreamStats; }; shards: { total: number; @@ -236,6 +238,45 @@ export interface APMUsage { >; } +export type MetricRollupIntervals = + | RollupInterval.OneMinute + | RollupInterval.TenMinutes + | RollupInterval.SixtyMinutes; + +export type MetricSupportingRollUp = + | 'service_destination' + | 'transaction' + | 'service_summary' + | 'service_transaction' + | 'span_breakdown'; + +export type MetricNotSupportingRollup = 'app'; + +export type MetricTypes = MetricSupportingRollUp | MetricNotSupportingRollup; + +export interface CapturedMetricStats { + total: { + shards: number; + docs: { + count: number; + }; + store: { + size_in_bytes: number; + }; + }; +} + +export interface LastDayCount { + doc_count: number; +} + +export interface DataStreamCombined { + all: CapturedMetricStats; + '1d': LastDayCount; +} + +export type DataStreamStats = Record; + export type APMDataTelemetry = DeepPartial; export type APMTelemetry = APMDataTelemetry; diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index fde387ee53caf..00651944940dc 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -4786,6 +4786,778 @@ } } } + }, + "metricset": { + "properties": { + "service_destination-1m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "service_destination-10m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "service_destination-60m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "transaction-1m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "transaction-10m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "transaction-60m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "service_summary-1m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "service_summary-10m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "service_summary-60m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "service_transaction-1m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "service_transaction-10m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "service_transaction-60m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "span_breakdown-1m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "span_breakdown-10m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "span_breakdown-60m": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + }, + "app": { + "properties": { + "all": { + "properties": { + "total": { + "properties": { + "shards": { + "type": "long", + "_meta": { + "description": "Total number of shards for the given metricset per rollup interval." + } + }, + "docs": { + "properties": { + "count": { + "type": "long", + "_meta": { + "description": "Total number of metric documents in the primary shard for the given metricset per rollup interval" + } + } + } + }, + "store": { + "properties": { + "size_in_bytes": { + "type": "long", + "_meta": { + "description": "Size of the metric index in the primary shard for the given metricset per rollup interval" + } + } + } + } + } + } + } + }, + "1d": { + "properties": { + "doc_count": { + "type": "long", + "_meta": { + "description": "Document count for the last day for a given metricset and rollup interval" + } + } + } + } + } + } + } } } }, From 307234384db35946d58fc122c9794e1b5b16e49c Mon Sep 17 00:00:00 2001 From: Brad White Date: Tue, 26 Sep 2023 01:45:36 -0600 Subject: [PATCH 44/45] Switch Check Types to Commit Diff for on merge pipeline (#167206) ## Summary After merging #167060, `Check Types` is going to fail in the on merge pipeline until all type errors are triaged. For now, lets use the commit diff type check. --- .buildkite/pipelines/on_merge.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.buildkite/pipelines/on_merge.yml b/.buildkite/pipelines/on_merge.yml index 133004f468948..40e57e402f677 100644 --- a/.buildkite/pipelines/on_merge.yml +++ b/.buildkite/pipelines/on_merge.yml @@ -154,8 +154,11 @@ steps: - exit_status: '-1' limit: 3 - - command: .buildkite/scripts/steps/check_types.sh - label: 'Check Types' + - command: .buildkite/scripts/steps/check_types_commits.sh + label: 'Check Types Commit Diff' + # TODO: Enable in #166813 after fixing types + # - command: .buildkite/scripts/steps/check_types.sh + # label: 'Check Types' agents: queue: n2-16-spot timeout_in_minutes: 60 From 62f9b56c4cb0061682d857c3fb35150b13d91c0a Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Tue, 26 Sep 2023 10:28:13 +0200 Subject: [PATCH 45/45] [Cloud Security] use only available agent versions for Cloudformation and Cloud Shell parameters (#166198) ## Summary fixes - https://github.com/elastic/security-team/issues/7557 instead of using Kibana version for Cloudformation and Cloud Shell params in CNVM and CSPM integrations, check if the version of an agent that matches the current Kibana version actually available as an artifact. Relevant for serverless, where Kibana version points to not-yet released versions of Elastic Agent. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- .../public/hooks/use_agent_version.test.ts | 125 ++++++++++++++++++ .../fleet/public/hooks/use_agent_version.ts | 27 +++- 2 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 x-pack/plugins/fleet/public/hooks/use_agent_version.test.ts diff --git a/x-pack/plugins/fleet/public/hooks/use_agent_version.test.ts b/x-pack/plugins/fleet/public/hooks/use_agent_version.test.ts new file mode 100644 index 0000000000000..6cb1c8ee42248 --- /dev/null +++ b/x-pack/plugins/fleet/public/hooks/use_agent_version.test.ts @@ -0,0 +1,125 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { renderHook } from '@testing-library/react-hooks'; + +import { useAgentVersion } from './use_agent_version'; +import { useKibanaVersion } from './use_kibana_version'; +import { sendGetAgentsAvailableVersions } from './use_request'; + +jest.mock('./use_kibana_version'); +jest.mock('./use_request'); + +describe('useAgentVersion', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should return agent version that matches Kibana version if released', async () => { + const mockKibanaVersion = '8.8.1'; + const mockAvailableVersions = ['8.9.0', '8.8.1', '8.8.0', '8.7.0']; + + (useKibanaVersion as jest.Mock).mockReturnValue(mockKibanaVersion); + (sendGetAgentsAvailableVersions as jest.Mock).mockResolvedValue({ + data: { items: mockAvailableVersions }, + }); + + const { result, waitForNextUpdate } = renderHook(() => useAgentVersion()); + + expect(sendGetAgentsAvailableVersions).toHaveBeenCalled(); + + await waitForNextUpdate(); + + expect(result.current).toEqual(mockKibanaVersion); + }); + + it('should return the latest availeble agent version if a version that matches Kibana version is not released', async () => { + const mockKibanaVersion = '8.11.0'; + const mockAvailableVersions = ['8.8.0', '8.7.0', '8.9.2', '7.16.0']; + + (useKibanaVersion as jest.Mock).mockReturnValue(mockKibanaVersion); + (sendGetAgentsAvailableVersions as jest.Mock).mockResolvedValue({ + data: { items: mockAvailableVersions }, + }); + + const { result, waitForNextUpdate } = renderHook(() => useAgentVersion()); + + expect(sendGetAgentsAvailableVersions).toHaveBeenCalled(); + + await waitForNextUpdate(); + + expect(result.current).toEqual('8.9.2'); + }); + + it('should return the agent version that is <= Kibana version if an agent version that matches Kibana version is not released', async () => { + const mockKibanaVersion = '8.8.3'; + const mockAvailableVersions = ['8.8.0', '8.8.1', '8.8.2', '8.7.0', '8.9.2', '7.16.0']; + + (useKibanaVersion as jest.Mock).mockReturnValue(mockKibanaVersion); + (sendGetAgentsAvailableVersions as jest.Mock).mockResolvedValue({ + data: { items: mockAvailableVersions }, + }); + + const { result, waitForNextUpdate } = renderHook(() => useAgentVersion()); + + expect(sendGetAgentsAvailableVersions).toHaveBeenCalled(); + + await waitForNextUpdate(); + + expect(result.current).toEqual('8.8.2'); + }); + + it('should return the latest availeble agent version if a snapshot version', async () => { + const mockKibanaVersion = '8.10.0-SNAPSHOT'; + const mockAvailableVersions = ['8.8.0', '8.7.0', '8.9.2', '7.16.0']; + + (useKibanaVersion as jest.Mock).mockReturnValue(mockKibanaVersion); + (sendGetAgentsAvailableVersions as jest.Mock).mockResolvedValue({ + data: { items: mockAvailableVersions }, + }); + + const { result, waitForNextUpdate } = renderHook(() => useAgentVersion()); + + expect(sendGetAgentsAvailableVersions).toHaveBeenCalled(); + + await waitForNextUpdate(); + + expect(result.current).toEqual('8.9.2'); + }); + + it('should return kibana version if no agent versions available', async () => { + const mockKibanaVersion = '8.11.0'; + const mockAvailableVersions: string[] = []; + + (useKibanaVersion as jest.Mock).mockReturnValue(mockKibanaVersion); + (sendGetAgentsAvailableVersions as jest.Mock).mockResolvedValue({ + data: { items: mockAvailableVersions }, + }); + + const { result, waitForNextUpdate } = renderHook(() => useAgentVersion()); + + expect(sendGetAgentsAvailableVersions).toHaveBeenCalled(); + + await waitForNextUpdate(); + + expect(result.current).toEqual('8.11.0'); + }); + + it('should return kibana version if the list of available agent versions is not available', async () => { + const mockKibanaVersion = '8.11.0'; + + (useKibanaVersion as jest.Mock).mockReturnValue(mockKibanaVersion); + (sendGetAgentsAvailableVersions as jest.Mock).mockRejectedValue(new Error('Fetching error')); + + const { result, waitForNextUpdate } = renderHook(() => useAgentVersion()); + + expect(sendGetAgentsAvailableVersions).toHaveBeenCalled(); + await waitForNextUpdate(); + + expect(result.current).toEqual(mockKibanaVersion); + }); +}); diff --git a/x-pack/plugins/fleet/public/hooks/use_agent_version.ts b/x-pack/plugins/fleet/public/hooks/use_agent_version.ts index 32d0ee128ddcc..8c198dbc7773e 100644 --- a/x-pack/plugins/fleet/public/hooks/use_agent_version.ts +++ b/x-pack/plugins/fleet/public/hooks/use_agent_version.ts @@ -4,14 +4,15 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - import { useEffect, useState } from 'react'; +import semverRcompare from 'semver/functions/rcompare'; +import semverLt from 'semver/functions/lt'; import { useKibanaVersion } from './use_kibana_version'; import { sendGetAgentsAvailableVersions } from './use_request'; /** - * @returns The most recent agent version available to install or upgrade to. + * @returns The most compatible agent version available to install or upgrade to. */ export const useAgentVersion = (): string | undefined => { const kibanaVersion = useKibanaVersion(); @@ -21,12 +22,26 @@ export const useAgentVersion = (): string | undefined => { const getVersions = async () => { try { const res = await sendGetAgentsAvailableVersions(); - // if the endpoint returns an error, use the fallback versions - const versionsList = res?.data?.items ? res.data.items : [kibanaVersion]; + const availableVersions = res?.data?.items; + let agentVersionToUse; + + if ( + availableVersions && + availableVersions.length > 0 && + availableVersions.indexOf(kibanaVersion) === -1 + ) { + availableVersions.sort(semverRcompare); + agentVersionToUse = + availableVersions.find((version) => { + return semverLt(version, kibanaVersion); + }) || availableVersions[0]; + } else { + agentVersionToUse = kibanaVersion; + } - setAgentVersion(versionsList[0]); + setAgentVersion(agentVersionToUse); } catch (err) { - return; + setAgentVersion(kibanaVersion); } };